Last active
July 17, 2024 22:15
-
-
Save henri/fd7e367d853a3970bdf6c077cf7765da to your computer and use it in GitHub Desktop.
Phillips Hue Hub Logging / Notification
This file contains hidden or 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
#!/usr/bin/env ruby | |
# Copyright, All Rights Reserved Henri Shustak 2020 | |
# Released under the GNU/GPL v3 or later licence | |
# | |
# requirements: | |
# - node.js - for hueadm - just install via package macnageer - eg brew.sh | |
# - hueadm - https://github.com/bahamas10/hueadm | |
# - datezone - http://www.fresse.org/dateutils/#datezone | |
# | |
# | |
# notes : | |
# This tools is built for the version of date which ships with macOS. | |
# If you are running on FreeBSD etc, you may need to change some of the date options for expected opperation. | |
# Operating system detection requires refactoring. This is basic implimentation for testing. | |
# | |
# | |
# - Version History | |
# - 2.2 - Introduced error capture and reporting for motion sensors which have no last update value | |
# - 2.1 - Introduced reduced tempature sensor polling option | |
# - 2.0 - Introduced error capture and reporting for switches which have no last update value | |
# - 1.9 - Minor performance improvemets | |
# - 1.8 - Improved battery reporting time managment and bug fixes | |
# - 1.7 - Added support for battery level reporting | |
# - 1.6 - Added support for GNU/LINUX date functions | |
# - 1.5 - Added support for tempature reporting | |
# - 1.4 - Added heart beat log reporting | |
# - 1.3 - Improved human readability with improved tab spacing between columns | |
# - 1.2 - Added support for sensors and switches with space in their name | |
# - 1.1 - Support added for gathering switch data | |
# - 1.0 - All configuration takes place in the script | |
# | |
#HUEHUB_IP = "192.168.1.xxx" | |
#HUEHUB_KEY = "long string of digits" | |
#LOCAL_TZ = "Pacific/Auckland" | |
# to get time zone from hub | |
# hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" config | grep timezone | |
# Time in seconds between polling the hue hub. | |
# Lower values will give higher resolution but have the draw back of | |
# using more resources on the hub and system running this script. | |
HUBPOLLTIME = "10" | |
# Heart beat interval. | |
# This will report a heart beat to the log file. | |
# Allows the log to be read and from the log determin if this deamon is working | |
HEARTBEAT = "60" #(60 is one miniute) | |
HEARTBEAT_LOOP_COUNT = HEARTBEAT.to_i / HUBPOLLTIME.to_i | |
@HEARTBEAT_COUNTDOWN = "#{HEARTBEAT_LOOP_COUNT}".to_i | |
# Tempature check interval | |
# Higher values will result in less tempature sensor polling, which | |
# will result in longer time between tempature sensor updates. | |
# A setting of zero "0" will disable this feature resulting in | |
# tempature updates which are probably close to the value which is | |
# specified for HUBPOLLTIME. If enabled you will need to lower | |
# your TIME_BEAT value to a much lower value so that the TEMP_POLLTIME | |
# actually happens at the time specified. | |
@TEMP_POLLTIME = "300" # (300 is 5 miniutes / 0 disables this feature) | |
# Battery check interval | |
BATTERY_POLLTIME = "86400" # (86400 is 24 hours) | |
# operating system we are running | |
OS = `uname`.chomp | |
# local time zone - global script time management | |
# time beat basically results in @TIME_NOW being less accurate but lowers system calls | |
# using a ruby time library may be a better approach, research and measurement required | |
# note that the @TIME_BEAT value should always be set to a value which is lower than | |
# the @TEMP_POLLTIME value. | |
@TIME_NOW = `date +%s`.chomp | |
@TIME_BEAT = "120" # (3600 is 1 hour / 180 is 3 miniutes) | |
@TIME_BEAT_LOOP_COUNT = @TIME_BEAT.to_i / HUBPOLLTIME.to_i | |
@TIME_BEAT_COUNTDOWN = "#{@TIME_BEAT_LOOP_COUNT}".to_i | |
@TIME_BEAT_START = "true" | |
@sensors = [] | |
@switches = [] | |
@tempature_sensors = [] | |
# sanity checks and warnings | |
if @TIME_BEAT.to_i > @TEMP_POLLTIME.to_i && @TEMP_POLLTIME.to_i != 0 then | |
STDERR.puts "WARNING! : The configured \'@TIME_BEAT = \"#{@TIME_BEAT}\"\' value must be | |
decreased in order for \'@TEMP_POLLTIME = \"#{@TEMP_POLLTIME}\"\' value to be honored. | |
This is because the @TIME_NOW value would be updated at a slower rate than the TEMP_POLLTIME. | |
Alterativly, You could increase the @TEMP_POLLTIME value or set \'@TEMP_POLLTIME = \"0\"\' to disable | |
the tempature log limiting feature." | |
exit -20 | |
end | |
# build list of motion sensors | |
sensor_list = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensors | grep ZLLPresence` | |
sensor_list.each_line do |s| | |
#current_sensor = s.split(" ") | |
current_sensor = s.split(/\s{2,}/) | |
@sensors.push({"id" => "#{current_sensor[0]}", "name" => "#{current_sensor[1]}", "type" => "#{current_sensor[2]}", "last_updated_gmt_time_raw" => "", "last_updated_local_time_raw" => "", "last_updated_local_time_seconds_epoch" => "", "last_updated_local_human" => "", "motion_present" => "", "sensor_updated" => "false", "battery_percentage" => "", "battery_next_update" => "", "battery_updated" => "false", "sensor_last_update_error" => "false" }) | |
end | |
# build list of tempature sensors | |
tempature_sensor_list = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensors | grep ZLLTemperature` | |
tempature_sensor_list.each_line do |s| | |
current_tempature_sensor = s.split(/\s{2,}/) | |
@tempature_sensors.push({"id" => "#{current_tempature_sensor[0]}", "name" => "#{current_tempature_sensor[1]}", "type" => "#{current_tempature_sensor[2]}", "last_updated_gmt_time_raw" => "", "last_updated_local_time_raw" => "", "last_updated_local_time_seconds_epoch" => "", "last_updated_local_human" => "", "tempature" => "", "tempature_sensor_updated" => "false", "tempature_next_update" => "" }) | |
end | |
# build list of switches (just the dimmer - battery operated 4 button ones for now) | |
switch_list = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensors | grep ZLLSwitch` | |
switch_list.each_line do |s| | |
current_switch = s.split(/\s{2,}/) | |
@switches.push({"id" => "#{current_switch[0]}", "name" => "#{current_switch[1]}", "type" => "#{current_switch[2]}", "last_updated_gmt_time_raw" => "", "last_updated_local_time_raw" => "", "last_updated_local_time_seconds_epoch" => "", "last_updated_local_human" => "", "button_event" => "", "switch_updated" => "false", "battery_percentage" => "", "battery_next_update" => "", "battery_updated" => "false", "switch_last_update_error" => "false" }) | |
end | |
# Just an example if you need to get some data from a sensor. | |
# Below will list all the names of the sensors if that is something you want to do. Same logic can apply for lights | |
# sensors.each do |s| | |
# puts s["name"] | |
# end | |
def get_last_update_motion_from_sensors | |
@sensors.each do |s| | |
sensor_last_updated = s["last_updated_gmt_time_raw"] | |
sensor_battery_next_update = s['battery_next_update'] | |
# get sensor data | |
last_update_gmt =`hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep lastupdated: | awk -F ": " '{print $2}' | tr -d "'"`.chomp | |
#last_update_local =`datezone "#{LOCAL_TZ}" --from-zone=UTC "#{last_update_gmt}" | awk -F "+" '{print $1}'`.chomp | |
# catch errors on sensors - # important for disabled sensors during startup | |
if "#{last_update_gmt}" != "none" then | |
last_update_local =`datezone "#{LOCAL_TZ}" --from-zone=UTC "#{last_update_gmt}" | awk -F "+" '{print $1}'`.chomp | |
last_update_local_error = "false" | |
else | |
# Sensor ERROR! state detected | |
last_update_local = "2022-08-27T22:39:30" # made up date so other conversions do not fail - requires additional testing | |
last_update_local_error = "true" | |
end | |
if "#{OS.to_s}" == "Darwin" then | |
last_updated_local_time_seconds_epoch = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local} +%s`.chomp | |
last_update_local_human_readable = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local}`.chomp | |
else | |
last_updated_local_time_seconds_epoch = `date "+%s" -d #{last_update_local}`.chomp | |
last_update_local_human_readable = `date "+%a %d %b %Y %T %Z" -d #{last_update_local}`.chomp | |
end | |
# check if this is the first time the sensor has been updated in memory | |
if "#{sensor_last_updated}" == "" || "#{sensor_last_updated}" != "#{last_update_gmt}" || "#{last_update_local_error}" == "true" then | |
# update the sensor data sotred in the memory hash | |
s['last_updated_gmt_time_raw'] = "#{last_update_gmt}" | |
s['last_updated_local_time_raw'] = "#{last_update_local}" | |
s['last_updated_local_time_seconds_epoch'] = "#{last_updated_local_time_seconds_epoch}" | |
s['last_updated_local_human'] = "#{last_update_local_human_readable}" | |
# if the sensor has been updated also check the sensor for presence | |
sensor_current_presence = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep presence | awk -F ": " '{print $2}'`.chomp | |
s['motion_present'] = "#{sensor_current_presence}" | |
# update sensor update notification status | |
if "#{last_update_local_error}" != "true" then | |
# update sensor update notification status | |
s['sensor_updated'] = "true" | |
s['sensor_last_update_error'] = "false" | |
else | |
s['sensor_last_update_error'] = "true" | |
end | |
end | |
# check battery percentage | |
if "#{sensor_battery_next_update}" == "" || @TIME_NOW.to_i > sensor_battery_next_update.to_i then | |
s['battery_percentage'] = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep "battery: " | awk '{print $2}'`.chomp | |
s['battery_next_update'] = @TIME_NOW.to_i + BATTERY_POLLTIME.to_i | |
s['battery_updated'] = "true" | |
end | |
end | |
end | |
def get_last_update_from_tempature_sensors | |
@tempature_sensors.each do |s| | |
# tempature_sensor_next_update will only has a value if TEMP_POLL time is set | |
tempature_sensor_next_update = s["tempature_next_update"] | |
# if there is a TEMP_POLL time set wait for it otherwise proceed without TEMP_POLL delay | |
if "#{tempature_sensor_next_update}" == "" || @TIME_NOW.to_i > tempature_sensor_next_update.to_i then | |
if @TEMP_POLLTIME.to_i != 0 then | |
s['tempature_next_update'] = @TIME_NOW.to_i + @TEMP_POLLTIME.to_i | |
end | |
tempature_sensor_last_updated = s["last_updated_gmt_time_raw"] | |
# get sensor data | |
last_update_gmt =`hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep lastupdated: | awk -F ": " '{print $2}' | tr -d "'"`.chomp | |
last_update_local =`datezone "#{LOCAL_TZ}" --from-zone=UTC "#{last_update_gmt}" | awk -F "+" '{print $1}'`.chomp | |
if "#{OS.to_s}" == "Darwin" then | |
last_updated_local_time_seconds_epoch = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local} +%s`.chomp | |
last_update_local_human_readable = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local}`.chomp | |
else | |
last_updated_local_time_seconds_epoch = `date "+%s" -d #{last_update_local}`.chomp | |
last_update_local_human_readable = `date "+%a %d %b %Y %T %Z" -d #{last_update_local}`.chomp | |
end | |
# check if this is the first time the sensor has been updated in memory | |
# has the sensor has been updated also check the sensor for tempature | |
if "#{tempature_sensor_last_updated}" == "" || "#{tempature_sensor_last_updated}" != "#{last_update_gmt}" then | |
# update the sensor data stored in the memory hash | |
s['last_updated_gmt_time_raw'] = "#{last_update_gmt}" | |
s['last_updated_local_time_raw'] = "#{last_update_local}" | |
s['last_updated_local_time_seconds_epoch'] = "#{last_updated_local_time_seconds_epoch}" | |
s['last_updated_local_human'] = "#{last_update_local_human_readable}" | |
# check the sensor for updated tempature data | |
tempature_sensor_current_tempature = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep temperature | awk -F ": " '{print $2}' | head -n 1`.chomp | |
s['tempature'] = "#{tempature_sensor_current_tempature}".chomp | |
# update sensor updated status and next poll time (if enabled) | |
s['tempature_sensor_updated'] = "true" | |
end | |
end | |
end | |
end | |
def get_last_button_event_from_switches | |
@switches.each do |s| | |
switch_last_updated = s["last_updated_gmt_time_raw"] | |
switch_battery_next_update = s['battery_next_update'] | |
# get switch data | |
last_update_gmt =`hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep lastupdated: | awk -F ": " '{print $2}' | tr -d "'"`.chomp | |
if "#{last_update_gmt}" != "none" then | |
last_update_local =`datezone "#{LOCAL_TZ}" --from-zone=UTC "#{last_update_gmt}" | awk -F "+" '{print $1}'`.chomp | |
last_update_local_error = "false" | |
else | |
# Switch ERROR! state detected | |
last_update_local = "2022-08-27T22:39:30" # made up date so other conversions do not fail - requires additional testing | |
last_update_local_error = "true" | |
end | |
if "#{OS.to_s}" == "Darwin" then | |
last_updated_local_time_seconds_epoch = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local} +%s`.chomp | |
last_update_local_human_readable = `date -j -f "%Y-%M-%dT%H:%M:%S" #{last_update_local}`.chomp | |
else | |
last_updated_local_time_seconds_epoch = `date "+%s" -d #{last_update_local}`.chomp | |
last_update_local_human_readable = `date "+%a %d %b %Y %T %Z" -d #{last_update_local}`.chomp | |
end | |
# check if this is the first time the switch has been updated in memory | |
if "#{switch_last_updated}" == "" || "#{switch_last_updated}" != "#{last_update_gmt}" then | |
# update the switch data sotred in the memory hash | |
s['last_updated_gmt_time_raw'] = "#{last_update_gmt}" | |
s['last_updated_local_time_raw'] = "#{last_update_local}" | |
s['last_updated_local_time_seconds_epoch'] = "#{last_updated_local_time_seconds_epoch}" | |
s['last_updated_local_human'] = "#{last_update_local_human_readable}" | |
# if the button has been updated also check the button event | |
switch_button_event = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep " buttonevent: " | awk -F ": " '{print $2}'`.chomp | |
s['button_event'] = "#{switch_button_event}" | |
if "#{switch_last_updated}" != "" || "#{last_update_local_error}" == "true" then | |
if "#{last_update_local_error}" != "true" then | |
# update sensor update notification status | |
s['switch_updated'] = "true" | |
s['switch_last_update_error'] = "false" | |
else | |
s['switch_last_update_error'] = "true" | |
end | |
end | |
# check battery percentage | |
if "#{switch_battery_next_update}" == "" || @TIME_NOW.to_i > switch_battery_next_update.to_i then | |
s['battery_percentage'] = `hueadm -U "#{HUEHUB_KEY}" -H "#{HUEHUB_IP}" sensor #{s["id"]} | grep "battery: " | awk '{print $2}'`.chomp | |
s['battery_next_update'] = @TIME_NOW.to_i + BATTERY_POLLTIME.to_i | |
s['battery_updated'] = "true" | |
end | |
end | |
end | |
end | |
# Okay we will now poll the hue hub periodically and update the output based on the sensors information. | |
# puts "type\t\t name \t\t\t event \t updated" | |
while true | |
`sleep #{HUBPOLLTIME}` | |
# time beat - used to update @TIME_NOW | |
@TIME_BEAT_COUNTDOWN -= 1 | |
if @TIME_BEAT_COUNTDOWN <= 0 || @TIME_BEAT_START == "true" then | |
@TIME_BEAT_START = "false" | |
@TIME_BEAT_COUNTDOWN = @TIME_BEAT_LOOP_COUNT | |
@TIME_NOW = `date +%s`.chomp | |
# puts "timebeat \t\t\t \t\t \t\t #{@TIME_NOW}" | |
end | |
# report heart beat to log - used to heart beat to the log | |
@HEARTBEAT_COUNTDOWN -= 1 | |
if @HEARTBEAT_COUNTDOWN <= 0 then | |
heart_beat_time=`date` | |
@HEARTBEAT_COUNTDOWN = HEARTBEAT_LOOP_COUNT | |
puts "heartbeat \t\t\t \t\t \t\t #{heart_beat_time}" | |
end | |
get_last_update_motion_from_sensors | |
@sensors.each do |s| | |
sensor_updated = s["sensor_updated"] | |
sensor_name = s["name"] | |
sensor_motion = s["motion_present"] | |
sensor_last_update = s["last_updated_local_human"] | |
sensor_battery_updated = s["battery_updated"] | |
sensor_last_update_error_detected = s["sensor_last_update_error"] | |
if "#{sensor_updated}" == "true" || "#{sensor_battery_updated}" == "true" then | |
# make the tabs pretty - this is ugly and should be sorted with a better appraoch | |
if sensor_name.length <= 5 then | |
sensor_name_tab="\t\t\t\t" | |
else | |
if sensor_name.length <= 14 then | |
sensor_name_tab="\t\t\t" | |
else | |
sensor_name_tab="\t\t" | |
end | |
end | |
end | |
if "#{sensor_updated}" == "true" then | |
#update sensor so it is no loner true because we are reporting the change | |
s["sensor_updated"] = "false" | |
puts "motion\t\t #{sensor_name} #{sensor_name_tab} #{sensor_motion} \t\t #{sensor_last_update}" | |
end | |
# list battery information and any errors | |
if "#{sensor_battery_updated}" == "true" then | |
s["battery_updated"] = "false" | |
sensor_battery_percentage = s["battery_percentage"] | |
puts "m-battery\t #{sensor_name} #{sensor_name_tab} #{sensor_battery_percentage} \t\t #{sensor_last_update}" | |
# report errors | |
if "#{sensor_last_update_error_detected}" == "true" then | |
sensor_last_update_error_current_time = `date` | |
puts "m-error\t\t #{sensor_name} #{sensor_name_tab} \t\t #{sensor_last_update_error_current_time}" | |
end | |
end | |
end | |
get_last_update_from_tempature_sensors | |
@tempature_sensors.each do |s| | |
tempature_sensor_updated = s["tempature_sensor_updated"] | |
tempature_sensor_name = s["name"].chomp(" Temp") | |
tempature_sensor_tempature = s["tempature"] | |
tempature_sensor_last_update = s["last_updated_local_human"] | |
if "#{tempature_sensor_updated}" == "true" then | |
#update sensor so it is no loner true because we are reporting the change | |
s["tempature_sensor_updated"] = "false" | |
# make the tabs pretty - this is ugly and shoudl be sorted with a better appraoch | |
if tempature_sensor_name.length <= 5 then | |
tempature_sensor_name_tab="\t\t\t\t" | |
else | |
if tempature_sensor_name.length <= 14 then | |
tempature_sensor_name_tab="\t\t\t" | |
else | |
if tempature_sensor_name.length <= 19 then | |
tempature_sensor_name_tab="\t\t" | |
else | |
tempature_sensor_name_tab="\t" | |
end | |
end | |
end | |
puts "tempature\t #{tempature_sensor_name} #{tempature_sensor_name_tab} #{tempature_sensor_tempature} \t\t #{tempature_sensor_last_update}" | |
end | |
end | |
get_last_button_event_from_switches | |
@switches.each do |s| | |
switch_updated = s["switch_updated"] | |
switch_name = s["name"] | |
switch_button_event = s["button_event"] | |
switch_last_update = s["last_updated_local_human"] | |
switch_battery_updated = s["battery_updated"] | |
switch_last_update_error_detected = s["switch_last_update_error"] | |
if "#{switch_updated}" == "true" || "#{switch_battery_updated}" == "true" then | |
# make the tabs pretty - this is ugly and shoudl be sorted with a better appraoch | |
if switch_name.length <= 5 then | |
switch_name_tab="\t\t\t\t" | |
else | |
if switch_name.length <= 14 then | |
switch_name_tab="\t\t\t" | |
else | |
switch_name_tab="\t\t" | |
end | |
end | |
end | |
if "#{switch_updated}" == "true" then | |
# update sensor so it is no loner true because we are reporting the change | |
s["switch_updated"] = "false" | |
puts "switch\t\t #{switch_name} #{switch_name_tab} #{switch_button_event} \t\t #{switch_last_update}" | |
end | |
# list battery information and any errors | |
if "#{switch_battery_updated}" == "true" then | |
s["battery_updated"] = "false" | |
switch_battery_percentage = s["battery_percentage"] | |
puts "s-battery\t #{switch_name} #{switch_name_tab} #{switch_battery_percentage} \t\t #{switch_last_update}" | |
# report errors | |
if "#{switch_last_update_error_detected}" == "true" then | |
switch_last_update_error_current_time = `date` | |
puts "s-error\t\t #{switch_name} #{switch_name_tab} \t\t #{switch_last_update_error_current_time}" | |
end | |
end | |
end | |
end | |
exit | |
This file contains hidden or 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
This is the start of what may become a more comprehensive project for monitoring and logging Philips | |
Hue Motion Sensor Data and other devices connected to the Hue Hub. | |
At this stage the project is a simple script which may be invoked to start logging various data which is availbel from the Phillips Hue Hub (including motion sensor data). | |
By parsing the generated data it is possible to trigger events / notifications or activate other systems via the network / connected software / outputs. | |
This implimentation is a starting point and as time permits / people have interst, I am open to building a | |
project which is able to be more comprehensive with built in notifications / deamons / installation script. | |
At this stage, if you are looking to get notifiationcs on a phone, the best bet is to take a look at something like | |
PushOver, you just need to scan the output of this monitoring script and then send push a notification if you feel like | |
paramerers are being meet which would justify a notification such as motion being present on a certain sensor | |
at a certain time. | |
If you want to write a log file, just start the script and use the tee command to send the data out to a log file. | |
It is of course very likely you will want to store this data in a database and that can be arranged with a custom output | |
parser which will store any realivent data in what ever way makes sense to you. | |
Before running the script, you will need to set the API key and HueHub IP / DNS name within the script as well as | |
your local regions local. This early version has no config file, you just edit the script and then run it. | |
Details on different local names is availble from the datezone website which is used to perform the time zone | |
conversions from UTC to your local time. Please note that variuous dates and times are stored in the internal memory | |
data structrue. As such, if you want to extract something else for the log it is a matter of just changing the output | |
data. | |
Ideas and feed back are welcomed. If you have a hue hub and motion sensors and would like to see this develop into a more | |
mature project, then let me know. Also, just ping me if you are using this it would be good to know if I should develop this | |
for personal use or if there are others who would like to benifit from the development. At present the script is not sending | |
any telematry. | |
If you are using tempature data to control enviroment tempature, it is advised that you alter or even disable to TEMP_POLL | |
value so that you have more frequent or less frequent tempature updates, depending on your update frequency requirments. | |
# Ideas for Future Versions | |
(1) Have a configuration file or enviroment varables for the hue hub settings or just rely on hueadm for authenticaition | |
(2) Possibly add light sensor data from motion sensors to the output. | |
(3) Refactoring varios aspects. | |
(4) TimeZone reading from system. | |
(5) Improve output grouping of battery status information maybe with a stack which is pushed and popped or some other approach |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment