A custom Home Assistant integration that fetches random jokes from multiple sources and provides them as a sensor entity.
- π Fetches random jokes from multiple joke APIs
- π Random provider selection for variety
- π‘οΈ Fault tolerance - automatically tries alternative providers if one fails
- π Creates a sensor entity with state "OK" when successful
- π·οΈ Stores joke text, ID, and source as attributes (no 255 character state limitation)
- β° Configurable refresh interval (1-1440 minutes, default: 5 minutes)
- π€ AI-powered joke explanations using Home Assistant's AI integration
- βοΈ Easy configuration through Home Assistant UI
- π Supports options flow for changing settings
- π‘οΈ Robust error handling and logging
- π± HACS compliant for easy installation
- Open HACS in your Home Assistant instance
- Find "Jokes" in the integration list and install it
- Restart Home Assistant
- Go to Configuration > Integrations
- Click "+ Add Integration" and search for "Jokes"
Or open it directly from here:
- Download the latest release from the releases page
- Extract the contents
- Copy the
custom_components/ha_jokesfolder to your Home Assistantcustom_componentsdirectory - Restart Home Assistant
- Go to Configuration > Integrations
- Click "+ Add Integration" and search for "Jokes"
- Go to Settings β Devices & Services
- Click "+ Add Integration"
- Search for "Jokes"
- Set your desired refresh interval (1-1440 minutes, default: 5)
- Click "Submit"
- Go to Settings β Devices & Services
- Find the Jokes integration
- Click "Configure"
- Adjust the refresh interval as needed
- Select/de-select joke providers
- Click "Submit"
After installation, the integration creates a sensor entity:
- Entity ID:
sensor.joke - State: "OK" when successful, "Error" when failed
- Icon: π (mdi:emoticon-happy-outline)
The sensor provides the following attributes:
joke: The complete joke textjoke_id: Unique identifier for the jokesource: The joke provider that supplied the jokelast_updated: Timestamp of the last successful updaterefresh_interval: Current refresh interval in minutes
type: entity
entity: sensor.joke
attribute: joke
name: "Joke of the Moment"type: markdown
content: |
## π Joke
{{ state_attr('sensor.joke', 'joke') }}
*Last updated @ {{ as_datetime(state_attr('sensor.joke', 'last_updated')).strftime('%H:%M %d %b %Y') }}*
*Source: {{ state_attr('sensor.joke', 'source') }}*
type: markdown
content: |
## π Joke
{{ state_attr('sensor.joke', 'joke') }}
*Last updated: {{ relative_time(as_datetime(state_attr('sensor.joke', 'last_updated'))) }} ago*
*Source: {{ state_attr('sensor.joke', 'source') }}*
type: conditional
conditions:
- entity: sensor.joke
state: "OK"
card:
type: markdown
content: |
## π Today's Joke
{{ state_attr('sensor.joke', 'joke') }}
**Joke ID**: {{ state_attr('sensor.joke', 'joke_id') }}
**Source**: {{ state_attr('sensor.joke', 'source') }}
**Updated**: {{ state_attr('sensor.joke', 'last_updated') }}type: custom:button-card
entity: sensor.joke
name: Daily Joke
show_state: false
styles:
card:
- background-color: var(--primary-background-color)
- padding: 20px
- border-radius: 15px
name:
- font-size: 20px
- font-weight: bold
- color: var(--primary-text-color)
custom_fields:
joke: |
[[[
return `<div style="font-size: 16px; line-height: 1.5; margin-top: 10px;">
${states['sensor.joke'].attributes.joke}
</div>`
]]]
source: |
[[[
return `<div style="font-size: 12px; color: var(--secondary-text-color); margin-top: 10px;">
Source: ${states['sensor.joke'].attributes.source}
</div>`
]]]type: entities
title: Joke
entities:
- entity: sensor.joke
type: attribute
attribute: joke
name: Current Joke
- entity: sensor.joke
type: attribute
attribute: source
name: Source
icon: mdi:information-outline
- entity: sensor.joke
type: attribute
attribute: last_updated
name: Last Updated
icon: mdi:clock-outlineYou can use the sensor in automations:
automation:
- alias: "Announce Joke"
trigger:
- platform: state
entity_id: sensor.joke
attribute: joke
action:
- service: notify.mobile_app_your_phone
data:
title: "New Joke!"
message: "{{ state_attr('sensor.joke', 'joke') }}"The integration provides an ha_jokes.explain_joke service that uses Home Assistant's AI integration to explain the current joke in plain language. This is perfect for jokes that might have wordplay, cultural references, or puns that need clarification.
- Home Assistant AI integration must be configured (e.g., OpenAI, Google Generative AI, or Azure AI)
- A default AI conversation agent must be set up
From the Developer Tools:
- Go to Developer Tools β Actions
- Select the
ha_jokes.explain_jokeaction - Click "Perform Action"
In Automations:
automation:
- alias: "Explain Joke on Request"
trigger:
- platform: state
entity_id: input_boolean.explain_joke_trigger
to: "on"
action:
- service: ha_jokes.explain_joke
- service: notify.mobile_app_your_phone
data:
title: "Joke Explanation"
message: "{{ state_attr('sensor.joke_explanation', 'explanation') }}"In Scripts:
script:
get_joke_explanation:
sequence:
- service: ha_jokes.explain_joke
- delay:
seconds: 5
- service: notify.persistent_notification
data:
title: "Joke Explanation"
message: "{{ state_attr('sensor.joke_explanation', 'explanation') }}"After calling the explain_joke service, the explanation is stored in the sensor.joke_explanation entity:
- Entity ID:
sensor.joke_explanation - State: "Explained" when an explanation is available, "Not Explained" otherwise
- Attribute:
explanationcontains the AI-generated explanation
Example Lovelace Card:
type: vertical-stack
cards:
- type: markdown
content: |
## π Joke
{{ state_attr('sensor.joke', 'joke') }}
- type: button
name: Explain This Joke
icon: mdi:comment-question-outline
tap_action:
action: call-service
service: ha_jokes.explain_joke
- type: conditional
conditions:
- entity: sensor.joke_explanation
state: "Explained"
card:
type: markdown
content: |
### π‘ Explanation
{{ state_attr('sensor.joke_explanation', 'explanation') }}This integration fetches jokes from three different sources, automatically selecting them in random order and providing fault tolerance if one source is unavailable:
-
icanhazdadjoke.com - A curated collection of dad jokes
- Provides free access to dad jokes
- Returns jokes in JSON format with unique IDs
- No API key required
-
JokeAPI v2 - A RESTful API serving jokes
- Configured in safe mode (no explicit content)
- Returns single-line jokes only
- Free and open source
- No API key required
-
Official Joke API - A simple joke API
- Community-maintained joke collection
- Returns setup/punchline format jokes
- Free and open source
- No API key required
The integration randomly selects which provider to use for each joke request. If a provider fails to respond, it automatically tries the next provider, ensuring you always get a joke as long as at least one service is available.
-
Sensor shows "Error" state
- Check your internet connection
- Verify that at least one joke API is accessible
- Check Home Assistant logs for detailed error messages
- The integration will automatically try alternative providers
-
Integration not appearing
- Ensure you've restarted Home Assistant after installation
- Check that the
custom_components/ha_jokesfolder is in the correct location - Verify all required files are present
-
Jokes not updating
- Check the refresh interval setting
- Verify the sensor state is "OK"
- Check logs for any error messages
To enable debug logging for this integration, add the following to your configuration.yaml:
logger:
logs:
custom_components.ha_jokes: debugContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- Jokes provided by:
- icanhazdadjoke.com
- JokeAPI v2 by Sven Fehler
- Official Joke API by David Katz
- Integration developed for the Home Assistant community
