From d1a6eb17b2e9e8addbb2834e5bab329af7f7ba70 Mon Sep 17 00:00:00 2001 From: Hans Karlinius Date: Sat, 20 May 2017 10:21:29 +0200 Subject: [PATCH] Initial version --- HASS.pm | 154 +++++++++++++ .../EN/plugins/Assistant/html/images/icon.png | Bin 0 -> 42257 bytes .../Assistant/html/images/light_off.png | Bin 0 -> 858 bytes .../Assistant/html/images/light_on.png | Bin 0 -> 713 bytes HTML/EN/plugins/Assistant/settings.html | 11 + Plugin.pm | 203 ++++++++++++++++++ Settings.pm | 25 +++ install.xml | 20 ++ strings.txt | 17 ++ 9 files changed, 430 insertions(+) create mode 100644 HASS.pm create mode 100644 HTML/EN/plugins/Assistant/html/images/icon.png create mode 100644 HTML/EN/plugins/Assistant/html/images/light_off.png create mode 100644 HTML/EN/plugins/Assistant/html/images/light_on.png create mode 100644 HTML/EN/plugins/Assistant/settings.html create mode 100644 Plugin.pm create mode 100644 Settings.pm create mode 100644 install.xml create mode 100644 strings.txt diff --git a/HASS.pm b/HASS.pm new file mode 100644 index 0000000..7b54b85 --- /dev/null +++ b/HASS.pm @@ -0,0 +1,154 @@ +package Plugins::Assistant::HASS; + +use strict; +use JSON::XS::VersionOneAndTwo; +use threads::shared; + +use Slim::Networking::SimpleAsyncHTTP; +use Slim::Utils::Log; +use Slim::Utils::Prefs; + +my $log = logger('plugin.assistant'); + +my $url; +my $cache; + +my $prefs = preferences('plugin.assistant'); + + +sub init { + ($cache) = @_; + + $url = $prefs->get('connect'); + + #$pass = $prefs->get('pass'); +} + + +sub testHass { + + # TODO: + # empty api request + # if response message = "API running." then return true + # show in settings +} + + +sub getEntities { + my ( $client, $cb, $params, $args ) = @_; + + our $result :shared = []; + our $counter :shared = 0; + + if (defined $args->{'entity_ids'}) { + foreach my $entity_id(@{$args->{'entity_ids'}}) { + + $counter++; + Plugins::Assistant::HASS::getEntity( + $client, + sub { + my $entity = shift; + if (defined $entity) { + push @$result, $entity; + } + $counter--; + if ($counter <= 0) { + $cb->($result); + } + }, + $params, + { + entity_id => $entity_id, + }, + ); + } + } else { + + Plugins::Assistant::HASS::getEntity( + $client, + sub { + my $entities = shift; + foreach my $entity(@$entities) { + push @$result, $entity; + } + $cb->($result); + }, + $params, + {}, + ); + } +} + + +sub getEntity { + my ($client, $cb, $params, $args) = @_; + + my $localurl = $url.'states'; + if (defined $args->{'entity_id'}) { + $localurl = $localurl.'/'.$args->{'entity_id'}; + } + + $log->debug('Get Entity: ', $localurl); + + my $http = Slim::Networking::SimpleAsyncHTTP->new( + sub { + my $response = shift; + my $params = $response->params('params'); + my $result; + if ( $response->headers->content_type =~ /json/ ) { + $result = decode_json($response->content); + } + $cb->($result); + }, + sub { + $log->warn("Warning (".$localurl."): $_[1]"); + $cb->(); + }, + { + params => $params, + timeout => 5, + }, + ); + + $http->get( + $localurl, + 'Content-Type' => 'application/json', + 'charset' => 'UTF-8', + ); +} + + +sub toggleLightEntity { + my ($client, $cb, $params, $args) = @_; + + my $localurl = $url.'services/light/toggle'; + my $req->{'entity_id'} = $args->{'entity_id'}; + + my $http = Slim::Networking::SimpleAsyncHTTP->new( + sub { + my $response = shift; + my $params = $response->params('params'); + my $result; + if ( $response->headers->content_type =~ /json/ ) { + $result = decode_json($response->content); + } + $cb->($result); + }, + sub { + $log->error("error: $_[1]"); + $cb->(); + }, + { + timeout => 5, + }, + ); + + $http->post( + $localurl, + 'Content-Type' => 'application/json', + 'charset' => 'UTF-8', + encode_json($req) + ); +} + +1; diff --git a/HTML/EN/plugins/Assistant/html/images/icon.png b/HTML/EN/plugins/Assistant/html/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..04e1dade7004e4a0e25c781d9236e5c45417bb47 GIT binary patch literal 42257 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

U`n2-0eOsgN6PK3N_5IJvdy~gBx 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 NXsYR|)+yV^{0}W`I;{Wz literal 0 HcmV?d00001 diff --git a/HTML/EN/plugins/Assistant/html/images/light_off.png b/HTML/EN/plugins/Assistant/html/images/light_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3129f5876a5af62fb0d8cef70d703b39fa7ace09 GIT binary patch literal 858 zcmV-g1Eu_lP)Od3*@NY(w8d@-IlSQFfYTOkH1$EI!@C|$ppT(_PbV0Ai(wYHEwQhuv{*&SS$blp6B7@Yx7($1xl91QwaVo(b-P^>LL|;d6h(A@f1hZR*=$C& zTJ76_e^;$mquFeh9FpXUj7B4J9A|69W;u>SqtWPRAj9F1Ow&w^*eugDX*e9F3z<%* zY#&4lrIjDEkb z|Mu(qzVep(clo}rx3z*Gz+^JfKB*^@34$Qd*IHLsSE)UA$Ye=FZf|c>gUDn_LmnO; zQiI53Nkf*)Woi(aENRH+=VxjVnJj6@;o)Iw5Sc7#i0}KUL1eO|Ar}`HsX=72q#=z) zBQ=OjmNcYZucK0_Xh&2k71Zl>eGtw$TCJ9LNUPNX=Mty4%|l}x$5gFWwLLIat5u5Q zSpV-4&N(`r4vNL1@+(m+7SZW+!DC6C_@wq1@wA7luD)aUk42a z1F~&9aXZh2H)M=SeO~sh`>wTg&IA?nLmT9~ z^F-DB_{V4*xTDv{@)Z`mCNODaBu+2vc4dOVPMl@`}_M4 kLS*B6!8vld91O$2AL#tIh5g-%cK`qY07*qoM6N<$f_u}9^#A|> literal 0 HcmV?d00001 diff --git a/HTML/EN/plugins/Assistant/html/images/light_on.png b/HTML/EN/plugins/Assistant/html/images/light_on.png new file mode 100644 index 0000000000000000000000000000000000000000..ad61ae9cca107018262517932f26c3df42692e8d GIT binary patch literal 713 zcmV;)0yh1LP)x zK~!ko?b^+28bKJx@$am=nnfYTmqQ^r=H*-n4GrWJTIj)B>8brUa>+l^Yp-n%=|7NA z0)ZTY*9fVw20SR9))x%!(}QEr>h6rJ_<$F2e&a{yaYk3wYPBSaB7EPcSS;ds9%-vi zr-LIRh)8M?0M%-B3K@^bsYT4{KP2ttiU^a*B;nXc;5YCGXag;M{~quLI0I_H+vKKf zHk(qf*Cl>MBJxv24rXmP$L&CmiDJ+004Swmz8rsnQ{XeuSYTX3k2%#DF?s|*L}EnT z0`GwP7#a6E<2D{-`MLo<0^I}_c~@uM*oHg45prh|@?sJ4ViMA}2x*&yyjq03 znuP3FgzT7v99o1NnuHu%gdCfM)GR`3CL!;EBMXQlJ(n?v16){uTrBkTmOM0m15OMg zPV^kcPrnZE1K2iz*w)#O4G6$K@C(>V5V55*_icY?Ki4PJVgiVw&N^Skj}HJJfQJMi z4?2rgL0D=jB%R@~CbfaAF=Tf|V-tsbXL{LS(c05viflGZ6h)NFWpcTkf&ZqMsZ1tAp-{m0 v{VBxrJZ4KQpU)FTQ9AmMKRcF6KxQ00000NkvXXu0mjfAe}A= literal 0 HcmV?d00001 diff --git a/HTML/EN/plugins/Assistant/settings.html b/HTML/EN/plugins/Assistant/settings.html new file mode 100644 index 0000000..dab2cd8 --- /dev/null +++ b/HTML/EN/plugins/Assistant/settings.html @@ -0,0 +1,11 @@ +[% PROCESS settings/header.html %] + + [% WRAPPER setting title="PLUGIN_ASSISTANT_CONNECT" desc="PLUGIN_ASSISTANT_CONNECT_DESC" %] + + [% END %] + + [% WRAPPER setting title="PLUGIN_ASSISTANT_PASS" desc="PLUGIN_ASSISTANT_PASS_DESC" %] + + [% END %] + +[% PROCESS settings/footer.html %] diff --git a/Plugin.pm b/Plugin.pm new file mode 100644 index 0000000..7aeee48 --- /dev/null +++ b/Plugin.pm @@ -0,0 +1,203 @@ +package Plugins::Assistant::Plugin; + +use strict; +use base qw(Slim::Plugin::OPMLBased); +use JSON::XS::VersionOneAndTwo; +use threads::shared; +use feature qw(switch); + +use Slim::Utils::Log; +use Slim::Utils::Prefs; +use Slim::Utils::Strings qw(string cstring); + +use Plugins::Assistant::HASS; + +my $log = Slim::Utils::Log->addLogCategory( + { + 'category' => 'plugin.assistant', + 'defaultLevel' => 'DEBUG', + 'description' => 'PLUGIN_ASSISTANT', + } +); + +my $prefs = preferences('plugin.assistant'); + +my $cache = Slim::Utils::Cache->new('assistant', 3); + + +sub initPlugin { + my $class = shift; + + if (my $username = $prefs->get('connect')) { + $prefs->set('connect', '') if $username eq '_assistant_'; + } + + $prefs->init( + { + connect => '_assistant_' + } + ); + + Plugins::Assistant::HASS->init($cache); + + $class->SUPER::initPlugin( + feed => \&handleFeed, + tag => 'assistant', + menu => 'radios', + is_app => 1, + weight => 1, + ); + + if (main::WEBUI) { + require Plugins::Assistant::Settings; + Plugins::Assistant::Settings->new(); + } +} + +sub getDisplayName { 'PLUGIN_ASSISTANT' } + +# don't add this plugin to the Extras menu +sub playerMenu {} + + +sub handleFeed { + my ($client, $cb, $args) = @_; + + my $params = $args->{params}; + + # Only groups in first level + $args->{'onlygroups'} = 1; + + getItems($client,$cb,$params,$args); +} + + +sub getItems { + my ($client, $cb, $params, $args) = @_; + + Plugins::Assistant::HASS::getEntities( + $client, + sub { + my $entities = shift; + my $items = []; + + foreach my $entity(@$entities) { + my ($namespace, $name) = split('\.', $entity->{'entity_id'}, 2); + + my $order = 999; + if (defined $entity->{'attributes'}->{'order'}) { + $order = $entity->{'attributes'}->{'order'}; + } + + # If current entity is included in args and this is a group, + # change namespace to the namespace of all sub entities + # Note: Currently only light is supported + if ($namespace eq 'group' && $entity->{'entity_id'} eq $args->{'entity_id'}) { + $namespace = 'light'; + } + + $log->debug('Namespace: ', $namespace, ' Name: ', $name, ' - ', $order); + + if ($namespace eq 'group' && (!$entity->{'attributes'}->{'hidden'} || $entity->{'attributes'}->{'view'})) { + + # Add current to request list if all sub entities the same + # Add current entity id to args + # Note: Currently only light is supported + my $entity_ids = $entity->{'attributes'}->{'entity_id'}; + if (!grep(!/light\./, @{$entity_ids})) { + push @$entity_ids, $entity->{'entity_id'}; + } + + push @$items, + { + name => $entity->{'attributes'}->{'friendly_name'}, + order => $order, + type => 'link', + url => \&getItems, + passthrough => [ + { + entity_id => $entity->{'entity_id'}, + entity_ids => $entity_ids, + } + ] + }; + + } elsif ($namespace eq 'light' && !defined $args->{'onlygroups'}) { + + push @$items, + { + name => $entity->{'attributes'}->{'friendly_name'}, + image => 'plugins/Assistant/html/images/light_'.$entity->{'state'}.'.png', + order => $order, + type => 'link', + url => \&toggleLightEntity, + passthrough => [ + { + entity_id => $entity->{'entity_id'}, + state => $entity->{'state'}, + } + ], + nextWindow => 'refresh', + }; + + } elsif ($namespace eq 'sensor' && !defined $args->{'onlygroups'}) { + + push @$items, + { + name => $entity->{'attributes'}->{'friendly_name'}.' '.$entity->{'state'}.$entity->{'attributes'}->{'unit_of_measurement'}, + order => $order, + type => 'text', + }; + + } elsif (!defined $args->{'onlygroups'}) { + + push @$items, + { + name => $entity->{'attributes'}->{'friendly_name'}.' '.$entity->{'state'}, + order => $order, + type => 'text', + }; + + } + } + $items = [ sort { uc($a->{order}) cmp uc($b->{order}) } @$items ]; + $cb->( + { + items => $items, + } + ); + }, + $params, + { + entity_ids => $args->{'entity_ids'}, + }, + ); +} + + +sub toggleLightEntity { + my ($client, $cb, $params, $args) = @_; + + Plugins::Assistant::HASS::toggleLightEntity( + $client, + sub { + my $items = []; + + push @$items, + { + name => 'Toggled Light', + type => 'text', + showBriefly => 1, + }; + $cb->( + { + items => $items, + } + ); + }, + $params, + $args, + ); +} + +1; \ No newline at end of file diff --git a/Settings.pm b/Settings.pm new file mode 100644 index 0000000..dc1755b --- /dev/null +++ b/Settings.pm @@ -0,0 +1,25 @@ +package Plugins::Assistant::Settings; + +use strict; +use base qw(Slim::Web::Settings); + +use Slim::Utils::Prefs; + +my $prefs = preferences('plugin.assistant'); + + +sub name { + return 'PLUGIN_ASSISTANT'; +} + + +sub prefs { + return ($prefs, 'connect'); +} + + +sub page { + return 'plugins/Assistant/settings.html'; +} + +1; \ No newline at end of file diff --git a/install.xml b/install.xml new file mode 100644 index 0000000..0c6b735 --- /dev/null +++ b/install.xml @@ -0,0 +1,20 @@ + + + PLUGIN_ASSISTANT + Hans Karlinius + enabled + false + PLUGIN_ASSISTANT_DESCRIPTION + hans.karlinius@live.com + plugins/Assistant/html/images/icon.png + 517d7aef-1bfa-49a2-b4ed-b0117d997531 + Plugins::Assistant::Plugin + plugins/Assistant/settings.html + + Logitech Media Server + * + 7.6 + + 2 + 0.1 + diff --git a/strings.txt b/strings.txt new file mode 100644 index 0000000..fac259a --- /dev/null +++ b/strings.txt @@ -0,0 +1,17 @@ +PLUGIN_ASSISTANT + EN Assistant + +PLUGIN_ASSISTANT_DESCRIPTION + EN This is good + +PLUGIN_ASSISTANT_CONNECT + EN Home Assistant connect url + +PLUGIN_ASSISTANT_CONNECT_DESC + EN Should be the same as used for web access with addition of /api at the end like http://localhost:8123/api + +PLUGIN_ASSISTANT_PASS + EN Home Assistant API password + +PLUGIN_ASSISTANT_PASS_DESC + EN The password set for http request, when logging in to the webpage