#!/usr/bin/env python3
''' Check on esphome-devices '''
import os
import sys
from datetime import datetime
from aioesphomeapi import APIClient, ReconnectLogic, SensorState, APIConnectionError
import asyncio
import argparse
import logging
#import colorlog
import zeroconf
import common
sleepsec = 60
noise_psk = os.environ['el_esphome_api_psk']
async def main(args):
"""Connect to an ESPHome device and get details."""
log.debug('function main()')
# Establish connection
api = APIClient(
address=args.address,
port=6053,
password='',
noise_psk=noise_psk)
log.debug('Connecting')
try:
await api.connect(login=True)
except APIConnectionError as e:
log.error("esphome api connection error - %s", e)
sys.exit(1)
log.info('Connected. Api version: ' + str(api.api_version))
# Show device details
log.debug('Getting device info')
device = vars(await api.device_info())
log.info('Device name: ' + device['name'])
log.debug('Getting sensors')
rawsensors, _ = await api.list_entities_services()
sensors = {}
for sensor in rawsensors:
sensors[sensor.key] = vars(sensor)
if log.isEnabledFor(logging.DEBUG):
from pprint import pformat
log.debug('Sensors: \n' + pformat(sensors))
log.info('Disconnecting')
await api.disconnect()
def callback(state):
if type(state) == SensorState and state.missing_state == False:
log.debug('function callback(' + str(state) + ')')
sensor = sensors[state.key]
value = state.state
if 'accuracy_decimals' in sensor:
decimals = sensor['accuracy_decimals']
value = round(value, decimals) if decimals > 0 else round(value)
unit = sensor['unit_of_measurement'] if 'unit_of_measurement' in sensor else ''
device_class = sensor['device_class'] if 'device_class' in sensor else ''
log.info(sensor['name'] + ' ' + sensor['device_class'] + ' - ' + str(value) + str(unit))
common.statein(sensor['name'], value, device_class, unit, verbose=True)
async def on_connect() -> None:
log.debug('function on_connect()')
log.info('Connected to API')
try:
await api.subscribe_states(callback)
except APIConnectionError as e:
log.error("esphome api connection error - %s", e)
await api.disconnect()
except Exception as e:
log.error("catched exception - %s", e)
await api.disconnect()
async def on_disconnect() -> None:
log.debug('function on_disconnect()')
log.warning("Disconnected from API")
reconnect = ReconnectLogic(
client=api,
on_connect=on_connect,
on_disconnect=on_disconnect,
zeroconf_instance=zeroconf.Zeroconf()
)
await reconnect.start()
try:
while True:
try:
log.debug('Sleep for ' + str(sleepsec) + 's')
await asyncio.sleep(sleepsec)
except Exception as e:
log.error("catched exception - %s", e)
except KeyboardInterrupt:
log.error("Keyboard interrupt")
pass
except KeyboardInterrupt:
log.error("Keyboard interrupt")
await reconnect.stop()
finally:
log.info("Closing loop.")
if __name__ == "__main__":
# Logging
#handler = colorlog.StreamHandler()
#handler.setFormatter(colorlog.ColoredFormatter(
# "%(log_color)s%(levelname)s - %(message)s {%(filename)s:%(lineno)d}",
# log_colors={
# 'DEBUG': 'light_black',
# 'INFO': 'cyan',
# 'WARNING': 'yellow',
# 'ERROR': 'red',
# 'CRITICAL': 'red,bg_white'
# }))
#log = colorlog.getLogger(__name__)
#log.setLevel(logging.WARNING)
#log.addHandler(handler)
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
logging.basicConfig(format="%(levelname)s - %(message)s {%(filename)s:%(lineno)d}")
parser = argparse.ArgumentParser(description="Connect to an esphome-device and access the native api")
parser.add_argument( "-a", "--address", help="Address of esp-device to connect to")
parser.add_argument( "-v", "--verbose", help="Set logging to debug mode", action="store_true")
args = parser.parse_args()
# Verbose logging?
if args.verbose:
log.setLevel(logging.DEBUG)
log.debug('asyncio.run(main(args))')
asyncio.run(main(args))
print('Bottom of script. Exiting.')
sys.exit(0)