From e5c6abbf47a5a25c448ba1e042ece77fbbc7c306 Mon Sep 17 00:00:00 2001 From: H Plato Date: Tue, 19 Jan 2016 21:55:44 -0700 Subject: [PATCH 1/7] Homebridge configuration file generator --- code/common/homebridge_gen_config.pl | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 code/common/homebridge_gen_config.pl diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl new file mode 100644 index 000000000..8e1ccd740 --- /dev/null +++ b/code/common/homebridge_gen_config.pl @@ -0,0 +1,77 @@ +# cycle through + +my $port = $config_parms{homebridge_port}; +$port = 51826 unless ($port); +my $name = $config_parms{homebridge_name}; +$name = "Homebridge" unless ($name); +my $pin = $config_parms{homebridge_pin}; +$pin = "031-45-154" unless ($pin); +my $username = $config_parms{homebridge_username}; +$username = "CC:22:3D:E3:CE:30" unless ($username); +my $version = "1.0"; +my $filepath = $config_parms{data_dir} . "/homebridge_config.json"; +my $acc_count; +$v_generate_hb_config = new Voice_Cmd("Generate new Homebridge config.json file"); + +if (said $v_generate_hb_config) { + my $config_json = "{\n\t\"bridge\": {\n"; + $config_json .= "\t\t\"name\": " . $name . "\",\n"; + $config_json .= "\t\t\"username\": " . $username . "\",\n"; + $config_json .= "\t\t\"port\": " . $port . "\",\n"; + $config_json .= "\t\t\"pin\": " . $pin . "\"\n\t},\n"; + $config_json .= "\t\"description\": \"MH Generated HomeKit Configuration v" . $version . " " . &time_date_stamp(17) . "\",\n"; + + $config_json .= "\n\t\"accessories\": [\n"; + $acc_count = 0; + $config_json .= add_group("fan"); + $config_json .= add_group("switch"); + $config_json .= add_group("light"); + $config_json .= add_group("lock"); + $config_json .= add_group("garagedoor"); + $config_json .= add_group("blinds"); + + $config_json .= "\t\t}\n\t]\n}\n"; + print_log "Writing configuration to $filepath..."; + print_log $config_json; + file_write($filepath, $config_json); +} + + +sub add_group { + my ($type) = @_; + my %url_types; + $url_types{lock}{on} = "lock"; + $url_types{lock}{off} = "unlock"; + $url_types{blind}{on} = "up"; + $url_types{blind}{off} = "down"; + $url_types{garagedoor}{on} = "open"; + $url_types{garagedoor}{off} = "close"; + my $groupname = "HB__" . (uc $type); + my $group = &get_object_by_name($groupname); + print_log "gn=$groupname"; + return unless ($group); + my $text = ""; + for my $member (list $group) { + $text .= "\t\t},\n" if ($acc_count > 0 ); + $acc_count++; + $text .= "\t\t{\n"; + $text .= "\t\t\"accessory\": \"HttpMulti\",\n"; + my $name = $member->{object_name}; + $name =~ s/_/ /g; + $name =~ s/\$//g; + $name = $member->{label} if (defined $member->{label}); + $text .= "\t\t\"name\": \"" . $name . "\",\n"; + my $on = "on"; + $on = $url_types{$type}{on} if (defined $url_types{$type}{on}); + my $off = "off"; + $off = $url_types{$type}{off} if (defined $url_types{$type}{off}); + $text .= "\t\t\"" . $on . "_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$on . "\",\n"; + $text .= "\t\t\"" . $off . "_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$off . "\",\n"; + $text .= "\t\t\"brightness_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "light"); + $text .= "\t\t\"deviceType\": \"" . $type . "\"\n"; + } + return $text; +} + + + \ No newline at end of file From 39e9c538a7960d1dd37675f62de54f2ea30162e8 Mon Sep 17 00:00:00 2001 From: H Plato Date: Wed, 20 Jan 2016 16:29:44 -0700 Subject: [PATCH 2/7] Fixed some quotes --- code/common/homebridge_gen_config.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index 8e1ccd740..82effb0b8 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -15,10 +15,10 @@ if (said $v_generate_hb_config) { my $config_json = "{\n\t\"bridge\": {\n"; - $config_json .= "\t\t\"name\": " . $name . "\",\n"; - $config_json .= "\t\t\"username\": " . $username . "\",\n"; - $config_json .= "\t\t\"port\": " . $port . "\",\n"; - $config_json .= "\t\t\"pin\": " . $pin . "\"\n\t},\n"; + $config_json .= "\t\t\"name\": \"" . $name . "\",\n"; + $config_json .= "\t\t\"username\": \"" . $username . "\",\n"; + $config_json .= "\t\t\"port\": \"" . $port . "\",\n"; + $config_json .= "\t\t\"pin\": \"" . $pin . "\"\n\t},\n"; $config_json .= "\t\"description\": \"MH Generated HomeKit Configuration v" . $version . " " . &time_date_stamp(17) . "\",\n"; $config_json .= "\n\t\"accessories\": [\n"; From 032c2b018c91c39201fa4a41c0e87ca1d52747e9 Mon Sep 17 00:00:00 2001 From: H Plato Date: Wed, 20 Jan 2016 16:58:00 -0700 Subject: [PATCH 3/7] Added ports for URLs --- code/common/homebridge_gen_config.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index 82effb0b8..7815f582e 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -17,7 +17,7 @@ my $config_json = "{\n\t\"bridge\": {\n"; $config_json .= "\t\t\"name\": \"" . $name . "\",\n"; $config_json .= "\t\t\"username\": \"" . $username . "\",\n"; - $config_json .= "\t\t\"port\": \"" . $port . "\",\n"; + $config_json .= "\t\t\"port\": " . $port . ",\n"; $config_json .= "\t\t\"pin\": \"" . $pin . "\"\n\t},\n"; $config_json .= "\t\"description\": \"MH Generated HomeKit Configuration v" . $version . " " . &time_date_stamp(17) . "\",\n"; @@ -32,7 +32,7 @@ $config_json .= "\t\t}\n\t]\n}\n"; print_log "Writing configuration to $filepath..."; - print_log $config_json; + #print_log $config_json; file_write($filepath, $config_json); } @@ -65,9 +65,9 @@ sub add_group { $on = $url_types{$type}{on} if (defined $url_types{$type}{on}); my $off = "off"; $off = $url_types{$type}{off} if (defined $url_types{$type}{off}); - $text .= "\t\t\"" . $on . "_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$on . "\",\n"; - $text .= "\t\t\"" . $off . "_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$off . "\",\n"; - $text .= "\t\t\"brightness_url\": \"http://" . $Info{IPAddress_local} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "light"); + $text .= "\t\t\"" . $on . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$on . "\",\n"; + $text .= "\t\t\"" . $off . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$off . "\",\n"; + $text .= "\t\t\"brightness_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "light"); $text .= "\t\t\"deviceType\": \"" . $type . "\"\n"; } return $text; From f5bfd0dd944b0f4b47cb94357356ce182577af59 Mon Sep 17 00:00:00 2001 From: H Plato Date: Wed, 20 Jan 2016 19:08:44 -0700 Subject: [PATCH 4/7] Added in some comments --- code/common/homebridge_gen_config.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index 7815f582e..e96030ff2 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -1,4 +1,8 @@ -# cycle through +# Category = HomeKit Integration + +#@ This module generates a config.json to be used by the homebridge system +#@ To use several groups need to be set up: +#@ HB__ where type is LIGHT, LOCK, FAN, GARAGEDOOR, BLINDS, SWITCH my $port = $config_parms{homebridge_port}; $port = 51826 unless ($port); From c826b82c60e8d883045f7b485187ef3d2f7d535d Mon Sep 17 00:00:00 2001 From: H Plato Date: Sun, 31 Jan 2016 19:11:55 -0700 Subject: [PATCH 5/7] Added in support for thermostats --- code/common/homebridge_gen_config.pl | 70 ++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index e96030ff2..5e0bf5a7e 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -2,7 +2,13 @@ #@ This module generates a config.json to be used by the homebridge system #@ To use several groups need to be set up: -#@ HB__ where type is LIGHT, LOCK, FAN, GARAGEDOOR, BLINDS, SWITCH +#@ HB__ where type is LIGHT, LOCK, FAN, GARAGEDOOR, BLINDS, SWITCH, THERMOSTAT +#@ Thermostat control only tested with a few models. + +# TODO: +# Status Calls: determine if an object is on or off + +# read_url = "http://mh/sub?hb_status('$item')"; my $port = $config_parms{homebridge_port}; $port = 51826 unless ($port); @@ -12,7 +18,7 @@ $pin = "031-45-154" unless ($pin); my $username = $config_parms{homebridge_username}; $username = "CC:22:3D:E3:CE:30" unless ($username); -my $version = "1.0"; +my $version = "2"; my $filepath = $config_parms{data_dir} . "/homebridge_config.json"; my $acc_count; $v_generate_hb_config = new Voice_Cmd("Generate new Homebridge config.json file"); @@ -33,6 +39,7 @@ $config_json .= add_group("lock"); $config_json .= add_group("garagedoor"); $config_json .= add_group("blinds"); + $config_json .= add_group("thermostat"); $config_json .= "\t\t}\n\t]\n}\n"; print_log "Writing configuration to $filepath..."; @@ -65,17 +72,62 @@ sub add_group { $name =~ s/\$//g; $name = $member->{label} if (defined $member->{label}); $text .= "\t\t\"name\": \"" . $name . "\",\n"; - my $on = "on"; - $on = $url_types{$type}{on} if (defined $url_types{$type}{on}); - my $off = "off"; - $off = $url_types{$type}{off} if (defined $url_types{$type}{off}); - $text .= "\t\t\"" . $on . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$on . "\",\n"; - $text .= "\t\t\"" . $off . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$off . "\",\n"; - $text .= "\t\t\"brightness_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "light"); + if ($type eq "thermostat") { + $text .= "\t\t\"setpoint_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/sub?hb_thermo_setpoint(%27" . $member->{object_name} . "%27,%VALUE%)\",\n"; + } else { + my $on = "on"; + $on = $url_types{$type}{on} if (defined $url_types{$type}{on}); + my $off = "off"; + $off = $url_types{$type}{off} if (defined $url_types{$type}{off}); + $text .= "\t\t\"" . $on . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$on . "\",\n"; + $text .= "\t\t\"" . $off . "_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=" .$off . "\",\n"; + $text .= "\t\t\"brightness_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "light"); + $text .= "\t\t\"speed_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/SET;none?select_item=" . $member->{object_name} . "&select_state=%VALUE%\",\n" if ($type eq "fan"); + } $text .= "\t\t\"deviceType\": \"" . $type . "\"\n"; } return $text; } +sub hb_status { + my ($item) = @_; + my $object = &get_object_by_name($item); + my $state = $object->state; + my $status = "1 "; + $status = "0 " if (lc $state eq "off"); + print_log "Homebridge: Status request: item=$item status=$status\n"; + return "$status"; +} +sub hb_thermo_setpoint { + my ($item,$value) = @_; + print_log "Homebridge temperature change request for $item to $value"; + my $object = &get_object_by_name($item); + if (UNIVERSAL::isa($object,'Venstar_Colortouch')) { + print_log "Venstar Colortouch found"; + my $sp_delay = 0; + if ($object->get_sched() eq "on") { + print_log "Thermostat on a schedule, turning off schedule for override"; + $object -> set_schedule("off"); + $sp_delay = 5; + } + if (($object->get_mode() eq "cooling") or ($object->get_mode() eq "auto")) { + eval_with_timer '$' . $item . '->set_cool_sp(' . $value . ')";', $sp_delay; + } else { + eval_with_timer '$' . $item . '->set_heat_sp(' . $value . ')";', $sp_delay; + } + + } elsif (UNIVERSAL::isa($object,'Nest_Thermostat')) { + print_log "Nest Thermostat found"; + $object -> set_target_temp($value); + + } elsif (UNIVERSAL::isa($object,'Insteon::Thermostat')) { + print_log "Insteon Thermostat found"; + $object -> heat_setpoint($value); + #how to determine when to select heat or cooling? + #$object -> cool_setpoint($value)"; + } else { + print_log "Unsupported Thermostat type"; + } +} \ No newline at end of file From 60627604635390269fef09ad5eee6102e0062630 Mon Sep 17 00:00:00 2001 From: H Plato Date: Sat, 13 Feb 2016 15:56:30 -0700 Subject: [PATCH 6/7] Added in the temperature autocalc and ability to directly overwrite the homebridge config file --- code/common/homebridge_gen_config.pl | 61 +++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index 5e0bf5a7e..a32a8daba 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -20,6 +20,7 @@ $username = "CC:22:3D:E3:CE:30" unless ($username); my $version = "2"; my $filepath = $config_parms{data_dir} . "/homebridge_config.json"; +$filepath = $config_parms{homebridge_config_dir} . "/config.json" if (defined $config_parms{homebridge_config_dir}); my $acc_count; $v_generate_hb_config = new Voice_Cmd("Generate new Homebridge config.json file"); @@ -73,7 +74,9 @@ sub add_group { $name = $member->{label} if (defined $member->{label}); $text .= "\t\t\"name\": \"" . $name . "\",\n"; if ($type eq "thermostat") { - $text .= "\t\t\"setpoint_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/sub?hb_thermo_setpoint(%27" . $member->{object_name} . "%27,%VALUE%)\",\n"; + my $name2 = $member->{object_name}; + $name2 =~ s/\$//g; + $text .= "\t\t\"setpoint_url\": \"http://" . $Info{IPAddress_local} . ":" . $config_parms{http_port} . "/sub?hb_thermo_setpoint(%27" . $name2 . "%27,%VALUE%)\",\n"; } else { my $on = "on"; $on = $url_types{$type}{on} if (defined $url_types{$type}{on}); @@ -101,33 +104,69 @@ sub hb_status { sub hb_thermo_setpoint { my ($item,$value) = @_; - print_log "Homebridge temperature change request for $item to $value"; + print_log "Homebridge: Temperature change request for $item to $value"; my $object = &get_object_by_name($item); + if (UNIVERSAL::isa($object,'Venstar_Colortouch')) { - print_log "Venstar Colortouch found"; + print_log "Homebridge: Thermostat Venstar Colortouch found"; my $sp_delay = 0; if ($object->get_sched() eq "on") { print_log "Thermostat on a schedule, turning off schedule for override"; $object -> set_schedule("off"); $sp_delay = 5; } - if (($object->get_mode() eq "cooling") or ($object->get_mode() eq "auto")) { - eval_with_timer '$' . $item . '->set_cool_sp(' . $value . ')";', $sp_delay; + my $auto_mode = "" + $auto_mode = &calc_auto_mode($value,$object->get_temp()) if ($object->get_mode() eq "auto"); + print_log "Homebridge: Thermostat calc mode is $auto_mode" if ($auto_mode); + if (($object->get_mode() eq "cooling") or ($auto_mode eq "cool")) { + if ($sp_delay) { + eval_with_timer '$' . $item . '->set_cool_sp(' . $value . ');', $sp_delay; + } else { + $object -> set_cool_sp($value); + } } else { - eval_with_timer '$' . $item . '->set_heat_sp(' . $value . ')";', $sp_delay; + if ($sp_delay) { + eval_with_timer '$' . $item . '->set_heat_sp(' . $value . ');', $sp_delay; + } else { + $object -> set_heat_sp($value); + } } } elsif (UNIVERSAL::isa($object,'Nest_Thermostat')) { - print_log "Nest Thermostat found"; + print_log "Homebridge: Nest Thermostat found"; $object -> set_target_temp($value); } elsif (UNIVERSAL::isa($object,'Insteon::Thermostat')) { - print_log "Insteon Thermostat found"; - $object -> heat_setpoint($value); - #how to determine when to select heat or cooling? - #$object -> cool_setpoint($value)"; + print_log "Homebridge: Insteon Thermostat found"; + my $auto_mode = "" + $auto_mode = &calc_auto_mode($value) if ($object->get_mode() eq "auto"); + print_log "Homebridge: Thermostat calc mode is $auto_mode" if ($auto_mode); + if (($object->get_mode() eq "cool") or ($auto_mode eq "cool")) { + $object -> cool_setpoint($value); + } else { + $object -> heat_setpoint($value); + } } else { print_log "Unsupported Thermostat type"; } } + +sub calc_auto_mode { + my ($value,$intemp,$outtemp) = @_; + + my $mode = "heat"; + my $cool_threshold = 8; #set to cool if outside less + my $outside = ""; + $outside = $Weather{Outdoor} if (defined $Weather{TempOutdoor}); + $outside = $outtemp if (defined $outtemp); + my $inside = ""; + $inside = $Weather{Inside} if (defined $Weather{TempInside}); + $inside = $intemp if (defined $intemp); + $mode = "cool" if ($value < $inside); + $mode = "heat" if (($value - $cool_threshold) > $outside); + + return $mode; +} + + \ No newline at end of file From 623367b5d046a59711acf5e8064a37582d4be4ce Mon Sep 17 00:00:00 2001 From: H Plato Date: Sun, 28 Feb 2016 17:51:28 -0700 Subject: [PATCH 7/7] Added in thermostat and auto temp logic --- code/common/homebridge_gen_config.pl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/code/common/homebridge_gen_config.pl b/code/common/homebridge_gen_config.pl index a32a8daba..6bb2b1998 100644 --- a/code/common/homebridge_gen_config.pl +++ b/code/common/homebridge_gen_config.pl @@ -4,6 +4,7 @@ #@ To use several groups need to be set up: #@ HB__ where type is LIGHT, LOCK, FAN, GARAGEDOOR, BLINDS, SWITCH, THERMOSTAT #@ Thermostat control only tested with a few models. +#@ requires homebridge-httpmulti accessory: https://github.com/hplato/homebridge-httpmulti # TODO: # Status Calls: determine if an object is on or off @@ -20,7 +21,6 @@ $username = "CC:22:3D:E3:CE:30" unless ($username); my $version = "2"; my $filepath = $config_parms{data_dir} . "/homebridge_config.json"; -$filepath = $config_parms{homebridge_config_dir} . "/config.json" if (defined $config_parms{homebridge_config_dir}); my $acc_count; $v_generate_hb_config = new Voice_Cmd("Generate new Homebridge config.json file"); @@ -52,8 +52,8 @@ sub add_group { my ($type) = @_; my %url_types; - $url_types{lock}{on} = "lock"; - $url_types{lock}{off} = "unlock"; + $url_types{lock}{on} = "locked"; + $url_types{lock}{off} = "unlocked"; $url_types{blind}{on} = "up"; $url_types{blind}{off} = "down"; $url_types{garagedoor}{on} = "open"; @@ -115,7 +115,7 @@ sub hb_thermo_setpoint { $object -> set_schedule("off"); $sp_delay = 5; } - my $auto_mode = "" + my $auto_mode = ""; $auto_mode = &calc_auto_mode($value,$object->get_temp()) if ($object->get_mode() eq "auto"); print_log "Homebridge: Thermostat calc mode is $auto_mode" if ($auto_mode); if (($object->get_mode() eq "cooling") or ($auto_mode eq "cool")) { @@ -138,7 +138,7 @@ sub hb_thermo_setpoint { } elsif (UNIVERSAL::isa($object,'Insteon::Thermostat')) { print_log "Homebridge: Insteon Thermostat found"; - my $auto_mode = "" + my $auto_mode = ""; $auto_mode = &calc_auto_mode($value) if ($object->get_mode() eq "auto"); print_log "Homebridge: Thermostat calc mode is $auto_mode" if ($auto_mode); if (($object->get_mode() eq "cool") or ($auto_mode eq "cool")) { @@ -156,6 +156,7 @@ sub calc_auto_mode { my $mode = "heat"; my $cool_threshold = 8; #set to cool if outside less + $cool_threshold = $config_parms{homebridge_auto_sp_threshold} if (defined $config_parms{homebridge_auto_sp_threshold}); my $outside = ""; $outside = $Weather{Outdoor} if (defined $Weather{TempOutdoor}); $outside = $outtemp if (defined $outtemp); @@ -167,6 +168,5 @@ sub calc_auto_mode { return $mode; } - - \ No newline at end of file +