This content originally appeared on DEV Community and was authored by MHA
TL;DR
Using Home Assistant and Node-RED I receive actionable notifications on my android phone for Google Home alarms and timers. The notifications show all information, they are grouped and have a countdown.
I'm a big fan of the Google(Nest) smart devices and have multiple Hub and Mini devices in my smart home setup. Paired with Home Assistant and Node-RED I use them to control every device and automation flow.
Alarms & Timers
The alarm and timer functions on the devices are the most frequent used by me, I use them every day.
They work fine, but I'm missing some functionality to make them awesome.
- They don't show up on my phone
- I can't control them by phone
- When the device rings and I'm not in the same room I won't notice the alarm / timer ringing
Home Assistant Google Home integration
This week I discovered a new community integration called "Google Home" which exposes the alarms and timers as sensors in HA.
leikoilja / ha-google-home
Home Assistant Google Home custom component
I installed it via HACS and it works really nice, the sensor entities for alarms and timers are created per device.
I wondered if I could use it for some new automations which would add more functionality for me, especially have them as notifications on my phone.
Goal
- Show alarms and timers as notifications on my phone
- Let them countdown to the time they fire
- When they ring the notification should show this
- When I dismiss a notification the alarm / timer should be deleted
- If they are deleted on the google device the notification should be removed
Node-RED
I use Node-RED for all my automations, I like the way it visualizes the flows. It's often described as a low code solution, as a developer I like the option to apply code logic as well.
What you see next is the end result of some trial and error programming, usually I start with just 1 sensor input and a normal flow. Which I then finetune and often convert to a reusable subflow.
What the main flow will look like:
In the end result I wanted to have just 1 sublfow which would control everything, having multiple alarm and timer sensors as input.
The subflow
The top flow handles all input.
The bottom flow handles cleared notifications.
Top flow
- Parse the input from the sensors
- Determine if it is an alarm or timer sensor
- Cache the active items (with type and sensor info) in memory
- For every active item create/update a notification message
- For every inactive item make a clear_notification message
- Send the messages to the Call service node
Let's start with the "Parse alarms & timers" function node which does all the heavy lifting.
I use the "Setup" tab of the function node to set some defaults which are used in the flow:
// Set type defaults
const defaults = {
timer: {
id: 'timer_id',
label: '⏳',
items: 'timers',
name: 'Timers',
deleteService: 'delete_timer'
},
alarm: {
id: 'alarm_id',
label: '⏰',
items: 'alarms',
name: 'Alarms',
deleteService: 'delete_alarm'
},
}
flow.set('defaults', defaults);
The "Function" tab
const defaults = flow.get('defaults');
const service = env.get('service');
const messages = [];
let type = '';
if(!msg.data) {
return null;
}
// Determine type: alarm or timer
if(typeof msg.data.new_state.attributes.timers !== 'undefined' || typeof msg.data.old_state.attributes.timers !== 'undefined' ) {
type = 'timer';
} else if (typeof msg.data.new_state.attributes.alarms !== 'undefined' || typeof msg.data.old_state.attributes.alarms !== 'undefined') {
type = 'alarm';
} else {
return null;
}
const typeValues = defaults[type];
// Create a alarm/timer item ready to be used by the service
const createItem = (item, sensor, type, device) => {
const doneTime = new Date(item.fire_time * 1000).toTimeString().substr(0, 5);
let label = `${typeValues.label}`;
let vibration = '';
let chronometer = true;
if(item.status === 'ringing') {
label = item.label ? `${label} ${item.label} RINGING` : `${label} RINGING`;
vibration = '100, 1000, 100, 1000, 100, 100, 1000, 100, 1000, 100';
chronometer = false;
} else {
label = item.label ? `${label} ${doneTime} ${item.label}` : `${label} ${doneTime}`;
}
let title = label;
if(item.duration) {
title = `${label} (${item.duration})`;
}
return {
id: item[typeValues.id],
sensor: sensor,
device: device,
type: type,
status: item.status,
data:{
title: title,
message: `${device}`,
data: {
tag: item[typeValues.id],
chronometer: chronometer,
when: item.fire_time,
sticky: 'true',
group: typeValues.name,
vibrationPattern: vibration
}
}
}
};
const mapItems = (arr) => {
return arr.map((item) => { return createItem(item, msg.data.entity_id, type, msg.data.old_state.attributes.friendly_name) })
}
const activeItems = mapItems(msg.data.new_state.attributes[typeValues.items] || []).filter(item => item.status !== 'none');
const cachedItems = flow.get('cachedItems') || new Map();
// Update or create notifications for active items
activeItems.forEach((item) => {
messages.push({
payload: {
service: service,
data: item.data
}
});
cachedItems.set(item.id, item);
})
// Clear expired/deleted notifications
cachedItems.forEach((item, id) => {
const findItem = activeItems.find(newItem => newItem.id === id);
if(!findItem && item.sensor === msg.data.entity_id) {
messages.push({
payload: {
service: service,
data: {
message: 'clear_notification',
data: {
tag: id
}
}
}
});
cachedItems.delete(id);
}
})
flow.set('cachedItems', cachedItems);
// Send notifications as a stream
messages.forEach((msg) => node.send(msg));
// All done
node.done();
Bottom flow
- Detect cleared notifications
- Look it up in the cache
- When found call the delete_alarm/timer service
- Remove the item from the cache
const cachedItems = flow.get('cachedItems');
const defaults = flow.get('defaults');
// Find cleared item
const findItem = cachedItems.get(msg.payload.event.tag);
if(!findItem) {
return null
}
node.send(
{
payload: {
service: defaults[findItem.type].deleteService,
data: {
entity_id: findItem.sensor,
[defaults[findItem.type].id]: findItem.id
}
}
}
)
// Clean up
cachedItems.delete(findItem.id);
flow.set('cachedItems', cachedItems);
node.done();
How to use
- Import the subflow in NR:
- Then edit the Environment variable for the service:
- Add the subflow and connect some alarm and/or timer sensors as
events_state
nodes. - All done, try it by creating a alarm / timer on the google home device, within a few seconds you should receive the notification on your phone.
This content originally appeared on DEV Community and was authored by MHA
MHA | Sciencx (2021-04-12T22:37:52+00:00) Get Google Home alarms & timers as notifications. Retrieved from https://www.scien.cx/2021/04/12/get-google-home-alarms-timers-as-notifications/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.