Last active
July 23, 2023 07:21
-
-
Save ndfred/b373eeafc4f5b0870c1b8857041289a9 to your computer and use it in GitHub Desktop.
Fetch data from a Hildebrand Glow device over MQTT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
import logging | |
import json | |
import paho.mqtt.client as mqtt # pip3 install paho-mqtt | |
GLOW_LOGIN = "GLOW_LOGIN" | |
GLOW_PASSWORD = "GLOW_PASSWORD" | |
GLOW_DEVICE_ID = "GLOW_DEVICE_ID" | |
# Fields gathered from the ZigBee Smart Energy Standard document | |
# 0702: Metering | |
# - 00: Reading Information Set | |
# - 00: CurrentSummationDelivered: meter reading | |
# - 01: CurrentSummationReceived | |
# - 02: CurrentMaxDemandDelivered | |
# - 07: ReadingSnapshotTime (UTC time) | |
# - 14: Supply Status (enum): 0x2 is on | |
# - 02: Meter Status | |
# - 00: Status (bit map): 10 means power quality event | |
# - 03: Formatting | |
# - 00: UnitofMeasure (enum): 00 means kWh, 01 means m3 | |
# - 01: Multiplier | |
# - 02: Divisor | |
# - 03: SummationFormatting (bit map): | |
# 2B means 3 digits after the decimal point, 2 digits before the decimal point | |
# FB means 3 digits after the decimal point, 16 digits before the decimal point, | |
# no leading zeros | |
# - 04: DemandFormatting | |
# - 06: MeteringDeviceType: 00 means Electric Metering, 80 means Mirrored Gas Metering | |
# - 07: SiteID: MPAN encoded in UTF-8 | |
# - 08: MeterSerialNumber (string) | |
# - 12: AlternativeUnitofMeasure (enum) | |
# - 04: Historical Consumption | |
# - 00: InstantaneousDemand (signed): current consumption | |
# - 01: CurrentDayConsumptionDelivered | |
# - 30: CurrentWeekConsumptionDelivered | |
# - 40: CurrentMonthConsumptionDelivered | |
# - 0C: Alternative Historical Consumption | |
# - 01: CurrentDayConsumptionDelivered | |
# - 30: CurrentWeekConsumptionDelivered | |
# - 40: CurrentMonthConsumptionDelivered | |
# 0705: Prepayment | |
# - 00: Prepayment Information Set | |
# - 00: PaymentControlConfiguration (bit map) | |
# - 01: CreditRemaining (signed) | |
# 0708: Device Management | |
# - 01: Supplier Control Attribute Set | |
# - 01: ProviderName (string) | |
def on_connect(client, _userdata, _flags, result_code): | |
if result_code != mqtt.MQTT_ERR_SUCCESS: | |
logging.error("Error connecting: %d", result_code) | |
return | |
result_code, _message_id = client.subscribe("SMART/HILD/" + GLOW_DEVICE_ID) | |
if result_code != mqtt.MQTT_ERR_SUCCESS: | |
logging.error("Couldn't subscribe: %d", result_code) | |
return | |
logging.info("Connected and subscribed") | |
def on_message(_client, _userdata, message): | |
payload = json.loads(message.payload) | |
current_time = datetime.datetime.now().strftime("%H:%M:%S") | |
electricity_consumption = int(payload["elecMtr"]["0702"]["04"]["00"], 16) | |
electricity_daily_consumption = int(payload["elecMtr"]["0702"]["04"]["01"], 16) | |
electricity_weekly_consumption = int(payload["elecMtr"]["0702"]["04"]["30"], 16) | |
electricity_monthly_consumption = int(payload["elecMtr"]["0702"]["04"]["40"], 16) | |
electricity_multiplier = int(payload["elecMtr"]["0702"]["03"]["01"], 16) | |
electricity_divisor = int(payload["elecMtr"]["0702"]["03"]["02"], 16) | |
electricity_meter = int(payload["elecMtr"]["0702"]["00"]["00"], 16) | |
gas_daily_consumption = int(payload["gasMtr"]["0702"]["0C"]["01"], 16) | |
gas_weekly_consumption = int(payload["gasMtr"]["0702"]["0C"]["30"], 16) | |
gas_monthly_consumption = int(payload["gasMtr"]["0702"]["0C"]["40"], 16) | |
gas_multiplier = int(payload["gasMtr"]["0702"]["03"]["01"], 16) | |
gas_divisor = int(payload["gasMtr"]["0702"]["03"]["02"], 16) | |
gas_meter = int(payload["gasMtr"]["0702"]["00"]["00"], 16) | |
electricity_daily_consumption = electricity_daily_consumption * electricity_multiplier / electricity_divisor | |
electricity_weekly_consumption = electricity_weekly_consumption * electricity_multiplier / electricity_divisor | |
electricity_monthly_consumption = electricity_monthly_consumption * electricity_multiplier / electricity_divisor | |
electricity_meter = electricity_meter * electricity_multiplier / electricity_divisor | |
gas_daily_consumption = gas_daily_consumption * gas_multiplier / gas_divisor | |
gas_weekly_consumption = gas_weekly_consumption * gas_multiplier / gas_divisor | |
gas_monthly_consumption = gas_monthly_consumption * gas_multiplier / gas_divisor | |
gas_meter = gas_meter * gas_multiplier / gas_divisor | |
assert(int(payload["elecMtr"]["0702"]["03"]["00"], 16) == 0) # kWh | |
assert(int(payload["gasMtr"]["0702"]["03"]["01"], 16) == 1) # m3 | |
assert(int(payload["gasMtr"]["0702"]["03"]["12"], 16) == 0) # kWh | |
logging.info("Reading at %s", current_time) | |
logging.info("* electricity consumption: %dW", electricity_consumption) | |
logging.info("* daily electricity consumption: %.3fkWh", electricity_daily_consumption) | |
logging.info("* weekly electricity consumption: %.3fkWh", electricity_weekly_consumption) | |
logging.info("* monthly electricity consumption: %.3fkWh", electricity_monthly_consumption) | |
logging.info("* electricity meter: %.3fkWh", electricity_meter) | |
logging.info("* daily gas consumption: %.3fkWh", gas_daily_consumption) | |
logging.info("* weekly gas consumption: %.3fkWh", gas_weekly_consumption) | |
logging.info("* monthly gas consumption: %.3fkWh", gas_monthly_consumption) | |
logging.info("* gas meter: %.3fm3", gas_meter) | |
logging.info("Full payload: %s", json.dumps(payload, indent=2)) | |
def loop(): | |
logging.basicConfig(level=logging.DEBUG, format='%(message)s') | |
client = mqtt.Client() | |
client.username_pw_set(GLOW_LOGIN, GLOW_PASSWORD) | |
client.on_connect = on_connect | |
client.on_message = on_message | |
client.connect("glowmqtt.energyhive.com") | |
client.loop_forever() | |
if __name__ == "__main__": | |
loop() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
From my reading, lines 90/91 should be:
payload["gasMtr"]["0702"]["03"]["00"]
is the multiplier, so unrelated to the unit.payload["gasMtr"]["0702"]["03"]["12"]
is the enum describing the alternate unit of measure.You appear to be reading from 2 different units - with your aggregates being read in from the alternate meter reading in kWh, and your instantaneous usage being read in from the primary meter.
I would imagine it would be more reliable to simply read from the primary meter, and adjust the units to match the indicated unit?