States API cache

This commit is contained in:
Devmel Apps
2023-10-02 11:49:59 +02:00
parent 4f765b6109
commit 827a1fcdb8
4 changed files with 66 additions and 29 deletions
+4 -2
View File
@@ -4,9 +4,11 @@ FROM $BUILD_FROM
# Copy data for add-on # Copy data for add-on
COPY hassapi.class.php /home COPY hassapi.class.php /home
COPY callback.php /home COPY callback.php /home
COPY poststate.sh /home COPY state_post.sh /home
COPY states_get.sh /home
COPY run.sh / COPY run.sh /
RUN chmod a+x /home/poststate.sh RUN chmod a+x /home/state_post.sh
RUN chmod a+x /home/states_get.sh
RUN chmod a+x /run.sh RUN chmod a+x /run.sh
# Install AirSendWebService # Install AirSendWebService
+58 -26
View File
@@ -6,12 +6,8 @@ class HassAPI{
function __construct($BASE_HASS_API, $HASS_API_TOKEN) { function __construct($BASE_HASS_API, $HASS_API_TOKEN) {
$this->BASE_HASS_API = $BASE_HASS_API; $this->BASE_HASS_API = $BASE_HASS_API;
$this->HASS_API_TOKEN = $HASS_API_TOKEN; $this->HASS_API_TOKEN = $HASS_API_TOKEN;
$this->auto_include = false; $fbvalue = @file_get_contents('auto_include.cfg');
if($this->isAuthorized()){ $this->auto_include = filter_var($fbvalue, FILTER_VALIDATE_BOOLEAN);
$fbvalue = @file_get_contents('auto_include.cfg');
$this->auto_include = filter_var($fbvalue, FILTER_VALIDATE_BOOLEAN);
$this->loadStates();
}
} }
public function isAuthorized() { public function isAuthorized() {
@@ -24,7 +20,7 @@ class HassAPI{
return $this->auto_include; return $this->auto_include;
} }
function searchEntityId($uid) { function searchEntityId($uid) {
if($this->states){ if($this->loadStates()){
foreach ($this->states as $value) { foreach ($this->states as $value) {
if($value['entity_uid_sha256'] == $uid){ if($value['entity_uid_sha256'] == $uid){
return $value['entity_id']; return $value['entity_id'];
@@ -36,7 +32,7 @@ class HassAPI{
function searchEntitiesFromChannelAndType($channel, $type) { function searchEntitiesFromChannelAndType($channel, $type) {
$ret = array(); $ret = array();
if(isset($channel) && $this->states){ if(isset($channel) && $this->loadStates()){
foreach ($this->states as $value) { foreach ($this->states as $value) {
if(array_key_exists('attributes', $value) && array_key_exists('channel', $value['attributes'])){ if(array_key_exists('attributes', $value) && array_key_exists('channel', $value['attributes'])){
if(self::isChannelCompatible($channel, $value['attributes']['channel'])){ if(self::isChannelCompatible($channel, $value['attributes']['channel'])){
@@ -66,8 +62,10 @@ class HassAPI{
} }
function setState($entity_id, $type, $state, $timestamp_ms, $channel = null) { function setState($entity_id, $type, $state, $timestamp_ms, $channel = null) {
$reloadcache = false;
$attributes = null; $attributes = null;
if($entity_id == null && isset($channel)){ if($entity_id == null && isset($channel)){
$reloadcache = true;
//New entity //New entity
$entity_id = "sensor.".self::toUniqueChannelName($channel); $entity_id = "sensor.".self::toUniqueChannelName($channel);
$attributes = array('channel' => $channel); $attributes = array('channel' => $channel);
@@ -104,11 +102,13 @@ class HassAPI{
if(array_key_exists('state', $content) && $content['state'] == $state){ if(array_key_exists('state', $content) && $content['state'] == $state){
$state .= '+'; $state .= '+';
} }
$reloadcache = true;
} }
if($type === 'toggle'){ if($type === 'toggle'){
if(array_key_exists('state', $content) && $content['state'] == 'pressed'){ if(array_key_exists('state', $content) && $content['state'] == 'pressed'){
$state .= '+'; $state .= '+';
} }
$reloadcache = true;
} }
if($type === 'level'){ if($type === 'level'){
$is_cover = (stripos($entity_id, "cover.") !== false) ? true : false; $is_cover = (stripos($entity_id, "cover.") !== false) ? true : false;
@@ -131,14 +131,14 @@ class HassAPI{
unset($content['last_updated']); unset($content['last_updated']);
//$dti = DateTimeImmutable::createFromFormat('U.u', ($timestamp_ms/1000)); //$dti = DateTimeImmutable::createFromFormat('U.u', ($timestamp_ms/1000));
//$content['last_updated'] = $dti->format('Y-m-d').'T'.$dti->format('H:i:s').'+00:00'; //$content['last_updated'] = $dti->format('Y-m-d').'T'.$dti->format('H:i:s').'+00:00';
$this->postState($entity_id, $content); $this->state_post($entity_id, $content, $reloadcache);
return true; return true;
} }
return false; return false;
} }
function getState($entity_id){ function getState($entity_id){
if($this->states && isset($entity_id)){ if($this->loadStates() && isset($entity_id)){
foreach ($this->states as $value) { foreach ($this->states as $value) {
if($value['entity_id'] == $entity_id){ if($value['entity_id'] == $entity_id){
return $value; return $value;
@@ -253,31 +253,62 @@ class HassAPI{
return $result; return $result;
} }
private function postState($entity_id, $content){ private function state_post($entity_id, $content, $reloadcache = false){
$json = json_encode($content, JSON_FORCE_OBJECT); $json = json_encode($content, JSON_FORCE_OBJECT);
if(strpos($this->BASE_HASS_API, "supervisor") !== false){ if(strpos($this->BASE_HASS_API, "supervisor") !== false){
//Bug in supervisor proxy => use bash //Bug in supervisor proxy => use bash
exec('./poststate.sh "'.$entity_id.'" "'.base64_encode($json).'"', $output, $retval); exec('./state_post.sh "'.$entity_id.'" "'.base64_encode($json).'"', $output, $retval);
}else{ }else{
$res = HassAPI::request($this->BASE_HASS_API."/states/".$entity_id, $json, 'POST', $this->HASS_API_TOKEN); $res = HassAPI::request($this->BASE_HASS_API."/states/".$entity_id, $json, 'POST', $this->HASS_API_TOKEN);
} }
trigger_error("postState ".$entity_id." ".$content['state'], E_USER_NOTICE); trigger_error("state_post ".$reloadcache." : ".$entity_id." ".$content['state'], E_USER_NOTICE);
if($reloadcache){
$this->states_get_cache();
}
} }
private function states_get_cache(){
private function loadStates() { if(strpos($this->BASE_HASS_API, "supervisor") !== false){
$res = HassAPI::request($this->BASE_HASS_API."/states", null, 'GET', $this->HASS_API_TOKEN); //Bug in supervisor proxy => use bash
if($res !== false && isset($res) && is_array($res) && isset($res['data'])){ exec('./states_get.sh', $output, $retval);
$this->states = json_decode($res['data'], true); }else{
if($this->states){ $res = HassAPI::request($this->BASE_HASS_API."/states", null, 'GET', $this->HASS_API_TOKEN);
foreach ($this->states as &$value) { if($res !== false && isset($res) && is_array($res) && isset($res['data'])){
$h = str_split(hash('sha256', $value['entity_id']),12)[0]; file_put_contents("states.json", $res['data']);
$val = intval($h, 16);
$value['entity_uid_sha256'] = $val;
}
} }
} }
} }
private function loadStates() {
$ret = false;
if($this->states){
$ret = true;
}else{
if($this->isAuthorized()){
$loaded = false;
$data_age = @(time() - filemtime('states.json'));
if($data_age > 100){
$this->states_get_cache();
}
$data = @file_get_contents('states.json');
if(isset($data)){
$this->states = json_decode($data, true);
if($this->states){
foreach ($this->states as &$value) {
$h = str_split(hash('sha256', $value['entity_id']),12)[0];
$val = intval($h, 16);
$value['entity_uid_sha256'] = $val;
}
$loaded = true;
$ret = true;
}
}
if($loaded == false){
trigger_error("API GET states wrong response", E_USER_ERROR);
}
}
}
return $ret;
}
private static function request($url, $data = null, $method = 'GET', $token = null) { private static function request($url, $data = null, $method = 'GET', $token = null) {
$result = false; $result = false;
@@ -301,8 +332,9 @@ class HassAPI{
} }
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method)); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
if (isset($token)){ if (isset($token)){
$token = str_replace('"', "", $token); curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
$options = array(CURLOPT_HTTPHEADER => array('Content-Type: application/json' , "Authorization: Bearer ".$token)); curl_setopt($curl,CURLOPT_XOAUTH2_BEARER, $token);
$options = array(CURLOPT_HTTPHEADER => array('Content-Type: application/json'));
curl_setopt_array($curl, $options); curl_setopt_array($curl, $options);
} }
$result = array(); $result = array();
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/with-contenv bashio
curl -o states.json -s -X GET -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" -H "Content-Type: application/json" http://supervisor/core/api/states