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:
Preparing better logic variables
It does not matter what value you set.
Copy 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
Create the neccessary flows
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.