diff --git a/requirements.txt b/requirements.txt index a852959..7711555 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,6 @@ vl53l1x # For Home Assistant MQTT Sensor paho-mqtt homeassistant-mqtt-binding + +# For Philips Hue Counter +phue diff --git a/src/consolecounter.py b/src/console_counter.py similarity index 76% rename from src/consolecounter.py rename to src/console_counter.py index cbeabc8..f60c0cf 100644 --- a/src/consolecounter.py +++ b/src/console_counter.py @@ -1,5 +1,5 @@ -from peoplecounter import PeopleCounter -from sensor.vl53l1xsensor import VL53L1XSensor +from sensor.people_counter import PeopleCounter +from sensor.vl53l1x_sensor import VL53L1XSensor import logging counter = PeopleCounter(VL53L1XSensor()) diff --git a/src/homeassistantcounter.py b/src/home_assistant_counter.py similarity index 91% rename from src/homeassistantcounter.py rename to src/home_assistant_counter.py index af7c375..eeba02d 100644 --- a/src/homeassistantcounter.py +++ b/src/home_assistant_counter.py @@ -1,5 +1,5 @@ -from peoplecounter import PeopleCounter -from sensor.vl53l1xsensor import VL53L1XSensor +from sensor.people_counter import PeopleCounter +from sensor.vl53l1x_sensor import VL53L1XSensor import paho.mqtt.client as mqtt from HaMqtt.MQTTSensor import MQTTSensor from HaMqtt.MQTTUtil import HaDeviceClass diff --git a/src/interface/philips_hue.py b/src/interface/philips_hue.py new file mode 100644 index 0000000..0d09c4d --- /dev/null +++ b/src/interface/philips_hue.py @@ -0,0 +1,87 @@ +from phue import Bridge +from time import sleep +from pathlib import Path +import logging +import socket + + +class PhilipsHue (): + def __init__(self, config): + self.config = config + self.connect() + + def connect(self): + registered = Path(self.config['registered_file']).is_file() + success = False + while success == False: + try: + logging.info("Connecting to hue bridge") + self.bridge = Bridge(self.config['bridge_ip']) + self.bridge.connect() + success = True + except Exception as e: + logging.info("Failed to connect to bridge") + success = False + if registered == False: + logging.info("Trying again in 5 seconds..") + sleep(5) + else: + raise e + + logging.info("Connected to hue bridge") + if registered == False: + # register + logging.info("Saving registration") + Path(self.config['registered_file']).touch() + + def get_state(self): + return self.__execute__(lambda: self.bridge.get_api()) + + def get_scenes(self): + return self.__execute__(lambda: self.bridge.get_scene()) + + def get_scene_by_name(self, name): + for key, scene in self.get_scenes().items(): + if scene['name'] == name: + scene['id'] = key + return scene + return None + + def set_light(self, lights, command): + return self.__execute__(lambda: self.bridge.set_light(lights, command)) + + def get_light(self, id, command=None): + return self.__execute__(lambda: self.bridge.get_light(id, command)) + + def set_group(self, groups, command): + return self.__execute__(lambda: self.bridge.set_group(groups, command)) + + def get_group(self, id, command=None): + return self.__execute__(lambda: self.bridge.get_group(id, command)) + + def set_group_scene(self, group_name, scene_name): + scene_id = self.get_scene_by_name(scene_name)['id'] + return self.__execute__(lambda: self.set_group(group_name, self.create_conf({'scene': scene_id}))) + + def create_conf(self, conf): + if 'transitiontime' not in conf.keys(): + conf['transitiontime'] = self.config['transition_time'] + return conf + + def __execute__(self, function): + try: + return function() + except socket.timeout as e: + # Try to reconnect + logging.exception( + "Could not execute function. Trying to reconnect to bridge") + logging.exception(str(e)) + try: + self.connect() + except Exception as e: + logging.exception( + "Reconnect did not succeed, skipping execution") + logging.exception(str(e)) + return + # Now try again + return function() diff --git a/src/philips_hue_counter.py b/src/philips_hue_counter.py new file mode 100644 index 0000000..40cf0de --- /dev/null +++ b/src/philips_hue_counter.py @@ -0,0 +1,55 @@ +from interface.philips_hue import PhilipsHue +from sensor.people_counter import PeopleCounter +from sensor.vl53l1x_sensor import VL53L1XSensor +import logging + +hue_conf = { + 'bridge_ip': '', + 'transition_time': 10, # seconds + 'light_group': '', + # If file exists, application is considered 'registered' at the bridge + 'registered_file': 'smart_light_registered.bridge' +} + + +hue = PhilipsHue(hue_conf) +counter = PeopleCounter(VL53L1XSensor()) +peopleCount = 0 + +logging.getLogger().setLevel(logging.INFO) + + +def count_change(change: int) -> None: + global peopleCount + + # Are lights on at the moment? + previous_lights_state = hue.get_group(hue_conf['light_group'])['state']['any_on'] + + # Apply correction + if peopleCount <= 0 and previous_lights_state: + # User indicates, that people count was not actually 0 + peopleCount = 1 + logging.debug(f'People count corrected to {peopleCount}') + elif peopleCount > 0 and not previous_lights_state: + # User indicates, that people count was actually 0 + peopleCount = 0 + logging.debug(f'People count corrected to {peopleCount}') + + peopleCount += change + if peopleCount < 0: + peopleCount = 0 + logging.debug(f'People count changed by {change}') + + # Handle light + target_light_state = peopleCount > 0 + + # Return, if there is no change + if previous_lights_state == target_light_state: + return + + hue.set_group(hue_conf['light_group'], {'on': target_light_state}) + logging.debug(f'Light state changed to {target_light_state}') + + +counter.hookCounting(count_change) +counter.run() diff --git a/src/peoplecounter.py b/src/sensor/people_counter.py similarity index 100% rename from src/peoplecounter.py rename to src/sensor/people_counter.py diff --git a/src/sensor/tofsensor.py b/src/sensor/tof_sensor.py similarity index 100% rename from src/sensor/tofsensor.py rename to src/sensor/tof_sensor.py diff --git a/src/sensor/vl53l1xsensor.py b/src/sensor/vl53l1x_sensor.py similarity index 100% rename from src/sensor/vl53l1xsensor.py rename to src/sensor/vl53l1x_sensor.py