My solution relies on MacroDroid’s ability to transmit data via UDP. The UDP packet is sent to my existing Node-Red server where a flow converts it to MQTT. The process looks like this:
[MacroDroid] --(UDP)--> [Node-Red] --(MQTT)--> [MQTT Broker] --(MQTT)--> [Home-Assistant]
Two macros are needed, one for handling changes to the battery level and another for power connection status (so you know if the device is connected to AC or not). The macros format their measurements into JSON strings and transmit them, via UDP, to the Node-Red server on port 5010.
A Node-Red flow listens to UDP 5010 and converts the incoming JSON strings into MQTT topics. It publishes two topics:
phone/battery
phone/power
In Home Assistant, you need an MQTT Binary Sensor, for receiving the power topic, and an MQTT Sensor for the battery topic.
In binary_sensors.yaml
:
- platform: mqtt
name: "Phone Power"
state_topic: "phone/power"
device_class: connectivity
In sensors.yaml
:
- platform: mqtt
name: "Phone Battery"
state_topic: "phone/battery"
unit_of_measurement: "%"
device_class: battery
expire_after: 1200
Here’s an overview of the two macros I created. You’ll have to create them on your tablet.
Battery Level
- Trigger: When there’s any change in battery level.
- Action: Send the battery level as a JSON string via UDP to my Node-Red server on port 5010.
- Constraint: Do this only if the phone is connected to my home’s WiFi network.
Power Status
- Trigger: When there’s any change in power-connection status.
- Action: Send the power status as a JSON string via UDP to my Node-Red server on port 5010.
- Constraint: Do this only if the phone is connected to my home’s WiFi network.
I chose to have the JSON string contain both the power status and battery level. The items enclosed by square brackets are how you define MacroDroid variables.
"{"power": "[power]", "battery": [battery]}"
Upon evaluation, the JSON string can look like this (phone is connected to a power source and battery is at 78%):
{"power": "on", "battery": 78}
The Node-Red flow consists of four nodes:
- UDP Input node - Receives UDP packets on port 5010.
- JSON node - Converts the received JSON string into an object.
- Function node - Converts the JSON object into MQTT topics (
phone/power
and phone/battery
).
- MQTT Output node: Publishes MQTT topics.
Here’s the Node-red flow:
[
{
"id": "c399e80c.845e88",
"type": "udp in",
"z": "c08de27a.3035c",
"name": "",
"iface": "",
"port": "5010",
"ipv": "udp4",
"multicast": "false",
"group": "",
"datatype": "utf8",
"x": 120,
"y": 100,
"wires": [
[
"4714cd20.c8b364"
]
]
},
{
"id": "4714cd20.c8b364",
"type": "json",
"z": "c08de27a.3035c",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 290,
"y": 100,
"wires": [
[
"d72d6678.0b3888"
]
]
},
{
"id": "d72d6678.0b3888",
"type": "function",
"z": "c08de27a.3035c",
"name": "MQTT Converter",
"func": "if ((msg.payload.battery !== undefined) && (msg.payload.power !== undefined)) {\n var MsgList = [];\n var path = \"phone/\";\n msg.payload.power = msg.payload.power.toUpperCase();\n \n for (var key in msg.payload) {\n MsgList.push({topic:path + key, payload:msg.payload[key], qos:0, retain:true});\n }\n return [MsgList];\n}\n",
"outputs": 1,
"noerr": 0,
"x": 490,
"y": 100,
"wires": [
[
"7bf2e7d6.36dfc8"
]
]
},
{
"id": "7bf2e7d6.36dfc8",
"type": "mqtt out",
"z": "c08de27a.3035c",
"name": "",
"topic": "",
"qos": "",
"retain": "",
"broker": "a621bb5.8358248",
"x": 690,
"y": 100,
"wires": []
},
{
"id": "a621bb5.8358248",
"type": "mqtt-broker",
"z": "",
"name": "YourMQTTBrokerName",
"broker": "YourMQTTBrokerName",
"port": "1883",
"clientid": "YourMQTTclientID",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": ""
}
]
EDIT
If you don’t like “phone” as the root topic name, you can of course change it to whatever you want. You simply need to change it within the flow’s function node and in the two Home Assistant sensors.
EDIT
As a refinement, you can create a single macro that triggers on either battery or power changes.