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 0000000..04e1dad
Binary files /dev/null and b/HTML/EN/plugins/Assistant/html/images/icon.png differ
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 0000000..3129f58
Binary files /dev/null and b/HTML/EN/plugins/Assistant/html/images/light_off.png differ
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 0000000..ad61ae9
Binary files /dev/null and b/HTML/EN/plugins/Assistant/html/images/light_on.png differ
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