Battery tracking
Stay updated on low battery and devices that do not report.
Every hour I run a homeyscript to check battery status, and look for devices that have not reported last 24 hours. If the list of affected devices do differ from previous run, it will send a battery status report to a Telegram group like this:

First create two better logic string variables,
batterytext
and batterystatus
.
It does not matter what value you set.
batteryStatus2.js
let betterlogic = await Homey.apps.getApp({id: "net.i-dev.betterlogic"})
let getVar = async (name) => {
let x = await betterlogic.apiGet(name)
if (!x) throw new Error("Could not find variable [" + name + "]")
return x.value
}
let currentStatus = await getVar('batterystatus')
const devicesX = await Homey.devices.getDevices();
const devices = []
_.forEach(devicesX, device => {
devices.push(device)
})
const excludes = ['75602d03-9c02-4ad4-a29f-119313982878']
const isBattery = (x) => {
if (!x.hasOwnProperty('capabilities')) return false
if (_.includes(excludes, x.id) ) return false
return _.includes(x['capabilities'], 'measure_battery')
}
const lowBattery = (x) => {
if (x.up > (24*3600)) return true
if (x.battery < 35) return true
return false
}
const sf = (str) => {
return str.replace(/ /g, "\\ ")
}
const getIDstring = (entities) => {
let ids = _.map(entities, (x) => { return x.id })
ids = _.sortBy(ids)
console.log(ids)
return ids.join(',')
}
const batteryInfo = (x) => {
let info = {
name: x.name,
id: x.id,
battery: null,
driverUri: x.driverUri,
driverId: x.driverId,
batteries: x.energyObj.batteries
}
if (x.capabilitiesObj && x.capabilitiesObj.hasOwnProperty('measure_battery')) {
//console.log(x)
info.battery = x.capabilitiesObj.measure_battery.value
let updates = []
for (let key in x.capabilitiesObj) {
if (x.capabilitiesObj[key].lastUpdated) updates.push(Date.parse(x.capabilitiesObj[key].lastUpdated))
}
let mostRecent = _.max(updates)
// Seconds since last updated measurement from this entity
info.up = Math.floor((Date.now() - mostRecent)/1000.0)
}
info.lowBattery = (info.battery < 50)
info.noUpdateToday = (info.up > (24*3600))
info.alarm = (info.up > (24*3600)) || (info.battery < 35)
info.body = "battery,id=" + sf(info.id) + ",name=" + sf(info.name) + " battery=" + info.battery + ",upd=" + info.up +
",lowbatt=" + info.lowBattery + ",noupd=" + info.noUpdateToday + ",alarm=" + info.alarm + "\n"
return info
}
let batteryentities = _.filter(devices, isBattery)
batteryentities = _.map(batteryentities, batteryInfo)
batteryentities = _.filter(batteryentities, (x) => { return x.alarm })
// console.log(batteryentities)
let batterytext = ''
_.forEach(batteryentities, batt => {
if (batt.lowBattery) {
batterytext += batt.name + ' has low battery ' + batt.battery + '%' + "\n"
console.log(batt.name + ' has low battery ' + batt.battery + '%')
} else if (batt.noUpdateToday) {
batterytext += batt.name + ' has not reported today. Not in ' + Math.floor(batt.up/3600) + ' hours' + "\n"
console.log(batt.name + ' has not reported today. Not in ' + Math.floor(batt.up/3600) + ' hours')
}
})
let batterystatus = getIDstring(batteryentities)
if (currentStatus !== batterystatus) {
console.log(" ----- REPORTING -----")
betterlogic.apiPut("batterytext/" + encodeURIComponent(batterytext))
} else {
console.log(" - no report - ")
}
console.log("Store batterystatus: " + batterystatus)
betterlogic.apiPut("batterystatus/" + batterystatus)
return true
You will need two flows. One flow that runs the battery script regularly:

And one script that sends the prepared battery status message to telegram when it is updated:

The second action of the script above is to update a dakboard status display with the same message.