A custom Home Assistant integration that fetches random jokes from multiple sources and provides them as a sensor entity.
- π Fetches random jokes from 5 built-in sources β 3 family-friendly (on by default) plus 2 opt-in sources clearly marked
β οΈ not family-friendly - π 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"
The setup and options screens list every joke source. The two opt-in sources are labelled
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') }}The integration ships its own Lovelace card, custom:ha-jokes-card. It is bundled
with the integration and auto-registered β there is nothing to install in HACS and
no Lovelace resource to add by hand. After a restart, add a card to your dashboard, pick
"Jokes Card" from the card picker (or paste the YAML below).
The card shows the current joke in a styled quote, its source and how long ago it
updated, an Explain it button (triggers an AI explanation via ha_jokes.explain_joke),
a New joke button (fetches a fresh joke on demand), and a conditional explanation
panel that appears once an explanation has been generated. It uses your active theme's
colours, so it looks right in both light and dark mode.
The AI writes its explanation in Markdown, and the card renders it properly β bold emphasis, paragraphs, and numbered/bulleted lists β using Home Assistant's own Markdown renderer, so it matches the styling of the core Markdown card. Two-part jokes keep the line break between setup and punchline.
The card has a visual editor β pick it from the card picker and you get proper form controls for every option below, so there is no need to write YAML by hand.
The explanation panel clears itself whenever the joke changes (the New joke button, a manual refresh, or the automatic refresh interval), so you never see an explanation for a joke that is no longer on screen.
type: custom:ha-jokes-card
# all options below are optional β these are the defaults
entity: sensor.joke
explanation_entity: sensor.joke_explanation
title: Joke of the Moment
explanation_position: below
height: 0
width: 0
show_source: true
show_buttons: true| Option | Default | Description |
|---|---|---|
entity |
sensor.joke |
The joke sensor to display. |
explanation_entity |
sensor.joke_explanation |
Sensor holding the AI explanation. |
title |
Joke of the Moment |
Card heading. |
explanation_position |
below |
below stacks the explanation under the joke; side puts it alongside. side automatically falls back to stacking when the card is too narrow for two columns. |
height |
0 |
Minimum card height in px (0 = automatic). Useful to stop the card resizing as the explanation appears and disappears. |
width |
0 |
Maximum card width in px (0 = fill the column). |
show_source |
true |
Show the source/provider line. |
show_buttons |
true |
Show the Explain it / New joke buttons. |
If you'd rather not use the custom card, a built-in-cards-only alternative (plus an optional Mushroom variant) lives in
examples/joke-cards.yamlβ it works with core cards only.
This integration fetches jokes from several 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
-
Geek Jokes - Random one-liners
β οΈ Not family-friendly β despite the name, the feed is mostly Chuck Norris jokes with some crude/edgy content and no safe-mode filter. Disabled by default; opt in via the integration options- Returns single-line jokes
- Free, no API key required
-
Yo Mama Jokes - Roast-style "yo mama" jokes
β οΈ Not family-friendly (adult/roast humour) β disabled by default; opt in via the integration options- Returns single-line jokes
- Free, 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
- Geek Jokes by Sameer Kumar (unfiltered, opt-in)
- Yo Mama Jokes (adult/roast humour, opt-in)
- Integration developed for the Home Assistant community


