Grydgets allows you to easily create widget-based dashboards that update in real time, showing local and online data. It runs on anything that supports Python, PyGame, and SDL, from the oldest Raspberry Pi to a full-blown modern PC.
Note: while the vast majority of the codebase was originally written by me, my free time has been dwindling more and more. Recent changes have been almost entirely developed with Claude Code. I have reviewed and tested the output, and I am using Grydgets myself 24/7.
For now, the only way to run it is to clone the repository and set up all the dependencies with pip or uv.
git clone https://github.com/iamjackg/grydgets
# pip
python3 -m venv venv
pip install -r requirements.txt
venv/bin/python main.py
# uv
uv venv
uv pip install -r requirements.txt
uv run main.py
Configuration for Grydgets must be stored in a conf.yaml file in its main folder. A sample file is provided in the
repo.
These are the currently available options:
graphics:
fps-limit: 10
fb-device: '/dev/fb1'
x-display: ':0'
fullscreen: True
resolution: [480, 320]
logging:
level: infofb-device is only needed if you're using a non-standard display device, like an SPI screen on the Raspberry Pi.
Similarly, x-display is necessary if you're trying to start Grydgets via ssh, and the DISPLAY environment variable
is not properly set.
Grydgets can run in headless mode, rendering dashboards to image files instead of displaying them on screen. This is ideal for web dashboards, remote monitoring, or running on servers without displays or X servers.
In headless mode, Grydgets:
- Uses SDL's dummy video driver (no display or X server required)
- Renders to image files at configurable intervals
- Maintains a
latest.{format}symlink for easy web serving - Auto-manages disk usage by cleaning up old images
Configuration options:
headless:
enabled: true # Enable headless mode
output_path: "./headless_output" # Directory for saved images
render_interval: 60 # Seconds between renders
image_format: "png" # Format: png, jpg, jpeg, or bmp
filename_pattern: "grydgets_{timestamp}" # Pattern with {timestamp} and {sequence}
create_latest_symlink: true # Create latest.{format} symlink
keep_images: 100 # Keep last N images (0 = unlimited)Example
# conf.yaml
graphics:
fps-limit: 1
resolution: [1920, 1080]
fullscreen: false
headless:
enabled: true
output_path: "/var/www/html/dashboard"
render_interval: 60
image_format: "png"
create_latest_symlink: true
keep_images: 1440 # 24 hours at 1-minute intervalsImportant: Switching between headless and normal mode requires restarting Grydgets. Configuration hot-reload (SIGUSR1) will warn and skip the change if the enabled flag is modified.
Data providers allow you to fetch data in the background and share it across multiple widgets, eliminating redundant API calls. For example, if you have a widget for the weather forecast of each day of the week, a single provider can fetch all weather data once and make it available to all daily widgets.
Providers are configured in providers.yaml:
providers:
hass_calendar:
type: rest
url: !secret hass_calendar_url
headers:
Authorization: !secret hass_bearer_token
json_path: "events" # Extract this from response
jq_expression: 'map(select(.status == "active"))' # Further filter with jq
update_interval: 60 # Fetch every 60 seconds
jitter: 5 # Add random 0-5 second delay
weather_api:
type: rest
url: https://api.weather.com/current
method: GET
auth:
bearer: !secret weather_token
update_interval: 300type: Provider type. Currently onlyrestis supported.url: The URL to fetch from (required).method(optional): HTTP method (GET,POST,PUT,DELETE). Defaults toGET.headers(optional): Dictionary of HTTP headers.params(optional): Dictionary of query parameters.bodyorpayload(optional): Request body for POST/PUT requests.auth(optional): Authentication options (see Authentication Schemes).json_path(optional): Simple JSON path to extract from response (e.g.,"events[0].title").jq_expression(optional): jq expression for complex data transformations (e.g.,'.events[] | select(.active)').update_interval(optional): Seconds between fetches. Defaults to60.jitter(optional): Random seconds (0 to this value) added to update interval. Defaults to0.
Note: If both json_path and jq_expression are provided, json_path is applied first, then jq_expression processes the result. This allows you to pre-filter data before complex transformations.
The tree of widgets that composes your dashboard must be specified in a file called widgets.yaml in the main folder. A
sample file is included in the repository.
The top-level of your widgets.yaml defines options for the implicit main screen, which acts as a ScreenWidget container for your entire dashboard.
background_image(optional): The path to an image file to use as the background for the entire screen.background_color(optional): A color for the screen background, as a list of RGB or RGBA components. Defaults to[0, 0, 0](black).drop_shadow(optional): Iftrue, a drop shadow effect will be applied to the main content of the screen. Defaults tofalse.widgets: A list containing the root widget(s) of your dashboard. Note that theScreenWidgetcurrently only supports a single child widget.
Grydgets, as the name suggests, draws dashboards based on a series of widgets. Widgets are generally of two types: Normal and Container.
Normal widgets draw something specific on the screen: a clock, the result of a REST call, an image, etc.
Container widgets determine where and how other widgets appear. For example, a Grid widget allows you to lay other widgets out in a grid. They can also affect their appearance, for example by adding a label below or above another widget.
Most widgets support the following optional parameters:
name(optional): A unique name for the widget instance. This is used for logging and for identifying notifiable widgets. If not provided, the widget type name is used.
Widgets that make HTTP requests (e.g., rest, restimage, httpflip) often support an auth parameter. This is a dictionary specifying the authentication method:
bearer: A string representing a Bearer token.basic: An object containingusernameandpasswordstrings for Basic authentication.
Example auth configuration:
auth:
bearer: !secret my_bearer_token
# OR
auth:
basic:
username: myuser
password: mypasswordAll Container widgets take a children parameter, specifying the list of widgets they're going to contain.
A widget that allows you to place other widgets in a grid layout.
It supports the following parameters:
rows: The number of rows in the grid.columns: The number of columns in the grid.padding(optional): The amount of padding around each child widget, in pixels. Defaults to0.color(optional): A background color for the grid itself (the "empty" space between widgets or behind the entire grid), as a list of RGB or RGBA components.widget_color(optional): A background color for each child widget's cell, as a list of RGB or RGBA components.corner_radius(optional): The corner radius for the overall grid background, in pixels. Defaults to0.widget_corner_radius(optional): The corner radius for each child widget's background, in pixels. Defaults to0.image_path(optional): The path to an image file to use as the background for the entire grid.drop_shadow(optional): Iftrue, a drop shadow effect will be applied to the child widgets within the grid. Defaults tofalse.row_ratios(optional): A list representing the relative ratio of each row's height. E.g.,[1, 2]means the second row will be twice as tall as the first. If not provided, rows have equal height.column_ratios(optional): A list representing the relative ratio of each column's width. E.g.,[1, 2]means the second column will be twice as wide as the first. If not provided, columns have equal width.
Example:
- widget: grid
rows: 2
columns: 2
padding: 4
color: [50, 50, 50]
widget_color: [70, 70, 70, 180]
corner_radius: 10
widget_corner_radius: 5
row_ratios: [1, 2]
column_ratios: [1, 2]A widget that lets you add a text label above or below another widget. It can only have one child.
It supports the following parameters:
text: The text to display as the label.font_path(optional): The path to a ttf file to use as font for the label text.position(optional):aboveorbelowthe child widget. Defaults toabove.text_size(optional): The size of the label text in pixels.text_color(optional): The color of the label text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).
Example:
- widget: label
text: 'Random person'
position: below
text_size: 30
text_color: [255, 255, 0]
children:
- widget: rest # ... some child widgetA widget that will transition between each child widget at a specified interval, with custom easing and transition time.
It supports the following parameters:
interval(optional): How long to wait before switching to the following widget, in seconds. Defaults to5seconds.transition(optional): How long the animation for transitioning to the following widget should last, in seconds. Defaults to1second.ease(optional): Determines the ease factor of the transition animation. Higher values make the transition more abrupt at the beginning/end. Defaults to2.
Example:
- widget: flip
interval: 5
transition: 1
ease: 3
children:
- widget: text # first child
- widget: restimage # second childA specialized flip widget that determines which child widget to display based on an HTTP request response.
It supports the following parameters:
url: The URL to retrieve the value from.mapping: A dictionary where keys are expected response values (or extracted JSON paths) and values are thenameof the child widget to display.default_widget: Thenameof the child widget to display if the response value does not match any entry inmapping.json_path(optional): The path to the json item to extract from the HTTP response. If not provided, the raw response text is used.jq_expression(optional): jq expression to extract the comparison value from the JSON response. If bothjson_pathandjq_expressionare provided,json_pathis applied first.auth(optional): Authentication options (see Authentication Schemes).method(optional): The HTTP method to use (GETorPOST). Defaults toGET.payload(optional): A dictionary representing the JSON payload forPOSTrequests.update_frequency(optional): How often the HTTP request should be made, in seconds. Defaults to30seconds.
Inherited from flip widget:
interval(optional): How long to wait before checking for changes, in seconds. Defaults to5seconds.transition(optional): How long the animation for transitioning should last, in seconds. Defaults to1second.ease(optional): Determines the ease factor of the transition animation. Higher values make the transition more abrupt at the beginning/end. Defaults to2.
Example:
- widget: httpflip
default_widget: motioneye-cam
update_frequency: 60
url: "https://homeassistant.example.com/api/template"
method: POST
auth:
bearer: !secret hass_token
payload:
template: '{{ (now() > today_at("18:00")) and (now() - states.switch.sonoff_meter_plug_4_relay.last_changed).seconds < (60*60*2) }}'
mapping:
"False": main-cam
"True": other-cam
children:
- widget: restimage
name: main-cam
url: http://192.168.255.34/image.jpg
- widget: restimage
name: other-cam
url: 'https://motioneye.example.com/picture/13/current'A specialized flip widget that determines which child widget to display based on a time schedule. It inherits all parameters from flip widgets.
It supports the following parameters:
schedule: A dictionary mapping time strings (HH:MMformat) to thenameof the child widget to display at or after that time, until the next scheduled time.interval(optional): How long to wait before checking the schedule again, in seconds. Defaults to5seconds.transition(optional): How long the animation for transitioning to the following widget should last, in seconds. Defaults to1second.ease(optional): Determines the ease factor of the transition animation. Defaults to2.
Example:
- widget: scheduleflip
schedule:
"08:00": morning-widget
"18:00": evening-widget
children:
- widget: text
name: morning-widget
text: "Good Morning!"
- widget: text
name: evening-widget
text: "Good Evening!"A specialized container widget that superimposes a pill-shaped overlay on top of a base widget. Useful for adding badges, status indicators, or additional information overlays on images or complex widgets.
It supports the following parameters:
circular_mask(optional): Iftrue, applies a circular mask to the base (first) widget. Defaults tofalse.widget_background_color(optional): Background color for the masked widget when using circular mask. As RGB or RGBA.pill_background_color(optional): Background color for the pill overlay. As RGB or RGBA. Defaults to transparent.pill_width_percent(optional): Width of the pill as a percentage of container width (0.0-1.0). Defaults to0.8.pill_height_percent(optional): Height of the pill as a percentage of container height (0.0-1.0). Defaults to0.2.pill_position_x(optional): Horizontal center position of the pill (0.0-1.0). Defaults to0.5(centered).pill_position_y(optional): Vertical center position of the pill (0.0-1.0). Defaults to0.8(lower area).pill_corner_radius(optional): Corner radius for the pill shape in pixels. If not specified, the pill is fully rounded (semicircular ends).pill_size_relative_to_circle(optional): Iftrueandcircular_maskis enabled, the pill size is relative to the circle diameter. Defaults tofalse.children: Exactly 2 child widgets. First is the base widget, second is the overlay widget.
Example:
- widget: pill
circular_mask: true
widget_background_color: [40, 0, 40, 150]
pill_background_color: [0, 0, 0, 150]
pill_width_percent: 1.4
pill_height_percent: 0.25
pill_position_y: 0.85
pill_size_relative_to_circle: true
children:
- widget: restimage
url: "file://images/profile.png"
preserve_aspect_ratio: true
- widget: text
text: "Online"
font_path: 'OpenSans-Regular.ttf'
color: [0, 255, 0]
align: centerA container widget that can display a temporary text notification over its main child widget. It can only have one child.
It supports the following parameters:
font_path: The path to a ttf file to use as font for the notification text.padding(optional): The amount of padding around the notification text in pixels. Defaults to0.text_size(optional): The size of the notification text in pixels.color(optional): The default color of the notification text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).
To send a notification, send a POST HTTP request to the port configured in conf.yaml.
Example:
- widget: notifiabletext
name: fullscreen-notification
font_path: 'OpenSans-ExtraBold.ttf'
padding: 10
text_size: 100
children:
- widget: grid # ... main content widgetcurl -X POST \
-H "Content-Type: application/json" \
-d '{"widget": "fullscreen-notification", "text": "This is a test notification from curl!", "duration": 10}' \
http://192.168.1.1:5000/notifyA container widget that can display a temporary image notification over its main child widget. It can only have one child.
It supports the following parameters:
- No specific configuration parameters beyond the common
name.
TTo send a notification, send a POST HTTP request to the port configured in conf.yaml with url (of the image) and duration (optional, in seconds).
Example:
- widget: notifiableimage
name: fullscreen-notification-image
children:
- widget: notifiabletext # ... main content widget (which itself could be notifiable)curl -X POST \
-H "Content-Type: application/json" \
-d '{"widget": "fullscreen-notification-image", "url": "https://example.com/your_image.jpg"}' \
http://192.168.1.1:5000/notifyA simple widget that displays some text.
It supports the following parameters:
text(optional): The text to display. Defaults to an empty string''.text_size(optional): The size of the text in pixels. If not provided, it automatically adjusts to fit the widget's height.font_path(optional): The path to a ttf file to use as font. If not provided, Pygame's default font is used.color(optional): The color of the text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).padding(optional): The amount of padding around the text in pixels. Defaults to0.align(optional): The horizontal alignment for the text. One ofleft,center, orright. Defaults toleft.vertical_align(optional): The vertical alignment for the text. One oftop,center, orbottom. Defaults totop.
Example:
- widget: text
text: 'Hello Grydgets!'
text_size: 50
font_path: 'OpenSans-Regular.ttf'
color: [0, 255, 0]
align: center
vertical_align: centerA widget that displays a 24-hour clock at the top, and the current date at the bottom.
It supports the following parameters:
time_font_path: The path to a ttf file to use as font for the time.date_font_path: The path to a ttf file to use as font for the date.color(optional): The color of the time and date text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).background_color(optional): The background color for the clock widget, as a list of RGB or RGBA components.corner_radius(optional): The corner radius for the clock widget's background, in pixels. Defaults to0.
Example:
- widget: dateclock
time_font_path: 'OpenSans-ExtraBold.ttf'
date_font_path: 'OpenSans-Regular.ttf'
color: [255, 255, 255]
background_color: [0, 0, 0, 160]
corner_radius: 25A widget that makes periodic HTTP requests and displays the response text. It supports JSON extraction and custom formatting of the final text.
It supports the following parameters:
url: The URL to retrieve.json_path(optional): The path to the JSON item to extract from the HTTP response. Supports nested objects and array indexing (e.g.,address.cityoritems[0].name).jq_expression(optional): jq expression for complex data transformations (e.g.,.items[] | select(.active)). If bothjson_pathandjq_expressionare provided,json_pathis applied first.format_string(optional): A Python format string to be used to format the final text. The extracted value is passed as the first argument. Defaults to{}.method(optional): The HTTP method to use (GETorPOST). Defaults toGET.payload(optional): A dictionary representing the JSON payload forPOSTrequests.auth(optional): Authentication options (see Authentication Schemes).update_frequency(optional): How often the HTTP request should be made, in seconds. Defaults to30seconds.font_path(optional): The path to a ttf file to use as font. If not provided, Pygame's default font is used.text_size(optional): The size of the text in pixels. If not provided, it automatically adjusts to fit the widget's height.color(optional): The color of the text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).padding(optional): The amount of padding around the text in pixels. Defaults to0.align(optional): The horizontal alignment for the text. One ofleft,center, orright. Defaults tocenter.vertical_align(optional): The vertical alignment for the text. One oftop,center, orbottom. Defaults tocenter.
Example:
- widget: rest
url: 'https://jsonplaceholder.typicode.com/users/1'
json_path: 'address.city'
format_string: 'lives in {}'
text_size: 70
update_frequency: 60
auth:
bearer: !secret my_api_token
method: GETA widget that displays data from a configured data provider. Unlike rest widgets that make their own HTTP requests, provider widgets read from shared data providers defined in providers.yaml, allowing multiple widgets to efficiently share the same data source.
It supports the following parameters:
providers: A list containing exactly one provider name (e.g.,[hass_calendar]).data_path(optional): JSON path to extract from provider data.jq_expression(optional): jq expression to extract/transform provider data. If both are provided,data_pathis applied first.format_string(optional): Python format string for display. The value is passed as{value}. Defaults to"{value}".fallback_text(optional): Text to show on error or missing data. Defaults to"--".show_errors(optional): Iftrue, displays error messages instead of fallback text. Defaults tofalse.font_path(optional): Path to a ttf font file.text_size(optional): Text size in pixels.color(optional): The color of the text, as a list of RGB or RGBA components. Defaults to[255, 255, 255](white).padding(optional): The amount of padding around the text in pixels. Defaults to0.align(optional): The horizontal alignment for the text. One ofleft,center, orright. Defaults tocenter.vertical_align(optional): Vertical alignment (top,center,bottom). Defaults tocenter.
Example:
providers:
my_calendar:
type: rest
url: !secret calendar_api
update_interval: 60
widgets:
- widget: grid
rows: 3
children:
- widget: provider
providers: [my_calendar]
data_path: "[0].title"
fallback_text: "No events"
- widget: provider
providers: [my_calendar]
data_path: "[0].location"
- widget: provider
providers: [my_calendar]
jq_expression: '.[0].start | strptime("%Y-%m-%d") | strftime("%A")'A widget that renders data from providers using Home Assistant's Jinja2 template engine. This is useful for complex formatting that leverages Home Assistant's powerful template functions and filters.
It supports the following parameters:
providers: A list of provider names (can be multiple, e.g.,[calendar, weather]).template: Jinja2 template string. Each provider's data is available asprovider_<name>(e.g.,provider_calendar,provider_weather).hass_url: Home Assistant instance URL (required).hass_token: Home Assistant authentication token (required).fallback_text(optional): Text to show on error. Defaults to"--".font_path(optional): Path to a ttf font file.text_size(optional): Text size in pixels.vertical_align(optional): Vertical alignment. Defaults tocenter.
Example:
- widget: providertemplate
providers: [hass_calendar, weather_api]
hass_url: !secret hass_url
hass_token: !secret hass_token
template: |
{% set event = provider_hass_calendar[0] %}
{% set weather = provider_weather_api %}
{{ event.title }} at {{ event.start_time | as_timestamp | timestamp_custom('%I:%M %p') }}
Weather: {{ weather.temp }}°F
fallback_text: "Loading..."A specialized flip widget that conditionally displays child widgets based on data from a provider. Similar to httpflip, but reads from a shared provider instead of making its own HTTP requests.
It supports the following parameters:
providers: A list containing exactly one provider name.data_path(optional): JSON path to extract the comparison value from provider data.jq_expression(optional): jq expression to extract the comparison value.mapping: Dictionary mapping values to child widget names.default_widget: Name of the child widget to display by default or when no mapping matches.interval(optional): How often to check the provider for data changes, in seconds. Defaults to5seconds.transition(optional): Transition animation duration in seconds. Defaults to1.ease(optional): Easing factor for transition. Defaults to2.
On provider errors, the widget stays on the currently displayed child (does not switch).
Example:
providers:
camera_switch:
type: rest
url: https://homeassistant.example.com/api/template
method: POST
auth:
bearer: !secret hass_token
payload:
template: '{{ is_state("switch.camera_mode", "on") }}'
update_interval: 10
widgets:
- widget: providerflip
providers: [camera_switch]
default_widget: cam_a
transition: 0.5
mapping:
"True": cam_a
"False": cam_b
children:
- widget: restimage
name: cam_a
url: http://192.168.1.10/image.jpg
- widget: restimage
name: cam_b
url: http://192.168.1.11/image.jpgA widget that displays images from URLs contained in provider data. Similar to restimage, but reads the image URL from a provider. Supports both HTTP/HTTPS URLs and local file paths using the file:// protocol.
It supports the following parameters:
providers: A list containing exactly one provider name.data_path(optional): JSON path to extract the image URL from provider data.jq_expression(optional): jq expression to extract the image URL.fallback_image(optional): Path to a fallback image file to display on error.auth(optional): Authentication for fetching the image from HTTP/HTTPS URLs (not used forfile://URLs).preserve_aspect_ratio(optional): Iftrue, maintains the original image aspect ratio when scaling. Iffalse(default), the image is scaled to fill the container.show_errors(optional): Iftrue, displays error messages instead of a fallback image. Defaults tofalse.
The extracted URL can be:
- HTTP/HTTPS URL:
https://example.com/image.jpg - Local file path:
file:///path/to/image.jpg
Example:
providers:
camera_urls:
type: rest
url: https://api.example.com/cameras
json_path: "active_cameras"
update_interval: 30
widgets:
- widget: providerimage
providers: [camera_urls]
data_path: "[0].image_url"
fallback_image: "camera_offline.png"
# Example with file:// URLs
- widget: providerimage
providers: [local_images]
data_path: "current_image"
# Provider returns: {"current_image": "file:///home/user/images/photo.jpg"}A widget that makes periodic HTTP requests and displays the retrieved image file. It also supports extracting an image URL from a JSON response and retrieving that image. Supports both HTTP/HTTPS URLs and local file paths using the file:// protocol.
It supports the following parameters:
url: The URL to retrieve the image from (HTTP/HTTPS orfile://URL).json_path(optional): The path to the JSON item that contains an image URL to retrieve. If specified, the value at this path will be used as the actual image URL.jq_expression(optional): jq expression to extract the image URL from the JSON response. If bothjson_pathandjq_expressionare provided,json_pathis applied first.auth(optional): Authentication options for HTTP/HTTPS requests (see Authentication Schemes). Not used forfile://URLs.update_frequency(optional): How often the image should be refreshed, in seconds. Defaults to30seconds.preserve_aspect_ratio(optional): Iftrue, maintains the original image aspect ratio when scaling. Iffalse(default), the image is scaled to fill the container.
The URL (either directly specified or extracted via json_path/jq_expression) can be:
- HTTP/HTTPS URL:
https://example.com/image.jpg - Local file path:
file:///path/to/image.jpg
Examples:
# HTTP image
- widget: restimage
url: 'https://motioneye.example.com/picture/9/current/'
auth:
basic:
username: camera_user
password: camera_password
update_frequency: 10
# Local file
- widget: restimage
url: 'file:///home/user/images/current.jpg'
update_frequency: 5
# Extract URL from JSON (can return either HTTP or file:// URL)
- widget: restimage
url: 'https://api.example.com/current-image'
json_path: 'image_url'
update_frequency: 10A widget that displays a static image. Currently only accepts binary image data loaded from external code. This widget is primarily used internally by other widgets like NotifiableImageWidget, but can be directly configured with image_data (though this typically requires dynamic injection).
It supports the following parameters:
image_data(optional): Binary contents of the image to display. (Typically set dynamically)preserve_aspect_ratio(optional): Iftrue, maintains the original image aspect ratio when scaling. Iffalse(default), the image is scaled to fill the container.
A widget that displays the time for the next vehicle to arrive at a public transit stop, using the NextBus public API.
It supports the following parameters:
agency: The agency code, e.g.ttcfor the Toronto Transit Commission.stop_id: The stop ID to report on.route(optional): Limit results to a specific route tag (e.g.,506for a specific streetcar route).number(optional): The maximum number of upcoming arrival times to report. Defaults to1.font_path(optional): The path to a ttf file to use as font for the arrival times.text_size(optional): The size of the text in pixels.
For example, to show the next two arrival times of all TTC streetcars eastbound at Young & King:
- widget: nextbus
agency: ttc
stop_id: 15638
number: 2
font_path: 'OpenSans-Regular.ttf'
text_size: 40Grydgets supports hot-reloading configuration without restarting the application. Send a SIGUSR1 signal to the running process to reload both widget configuration and data providers:
kill -SIGUSR1 <process_id>This will:
- Stop all existing data providers
- Reload
providers.yamland restart providers - Reload
widgets.yamland rebuild the widget tree - Maintain the Flask notification server without interruption
Grydgets supports two methods for extracting data from JSON responses:
json_path - Simple path notation for basic extraction:
json_path: "events[0].title" # Get title of first event
json_path: "user.address.city" # Navigate nested objectsjq_expression - Powerful jq expressions for complex transformations:
jq_expression: '.events[] | select(.priority == "high")' # Filter
jq_expression: '.items | map(.name) | join(", ")' # Transform
jq_expression: '.[0].date | strptime("%Y-%m-%d") | strftime("%B %d")' # FormatCombining both - Use json_path to pre-filter, then jq for complex operations:
json_path: "events" # Extract events array first
jq_expression: 'map(select(.active)) | .[0].title' # Filter and extractThis works in:
- REST widgets (
rest,restimage,httpflip) - Data providers (
providers.yaml) - Provider widgets (
provider,providerflip,providerimage)
Grydgets runs a Flask server on the port specified in conf.yaml (default: 5000) that accepts POST requests to trigger notifications on widgets with the notifiable prefix.
Text Notifications:
curl -X POST -H "Content-Type: application/json" \
-d '{"widget": "fullscreen-notification", "text": "Hello!", "duration": 10}' \
http://localhost:5000/notifyImage Notifications:
curl -X POST -H "Content-Type: application/json" \
-d '{"widget": "image-notification", "url": "https://example.com/image.jpg", "duration": 5}' \
http://localhost:5000/notifyGrydgets supports a secrets.yaml file for storing sensitive configuration data. Use the !secret tag to reference secrets:
# secrets.yaml
hass_token: "your_secret_token_here"
api_key: "your_api_key"
# conf.yaml or widgets.yaml
auth:
bearer: !secret hass_tokenThe secrets.yaml file should not be committed to version control.
