. */ /* * ***************************Includes********************************* */ require_once __DIR__ . '/../../../../core/php/core.inc.php'; class aps_ecu extends eqLogic { /* * *************************Attributs****************************** */ const END_REQUEST_SUFFIX = "END\n"; const END_ECU_C_UID_PREFIX = "215"; const SOCKET_TIMEOUT = 10; const RECV_BUFFER_LENGTH = 4096; const SLEEP_DELAY = 1; /* * Permet de définir les possibilités de personnalisation du widget (en cas d'utilisation de la fonction 'toHtml' par exemple) * Tableau multidimensionnel - exemple: array('custom' => true, 'custom::layout' => false) public static $_widgetPossibility = array(); */ /* * Permet de crypter/décrypter automatiquement des champs de configuration du plugin * Exemple : "param1" & "param2" seront cryptés mais pas "param3" public static $_encryptConfigKey = array('param1', 'param2'); */ /* * ***********************Methode static*************************** */ /* * Fonction exécutée automatiquement toutes les minutes par Jeedom * public static function cron() { } */ /* * Fonction exécutée automatiquement toutes les 5 minutes par Jeedom */ public static function cron5() { foreach (self::byType('aps_ecu', true) as $plugin) { $cmd = $plugin->getCmd(null, 'refresh'); if (!is_object($cmd)) { continue; } $cmd->execCmd(); } } /* * Fonction exécutée automatiquement toutes les 10 minutes par Jeedom public static function cron10() {} */ /* * Fonction exécutée automatiquement toutes les 15 minutes par Jeedom public static function cron15() {} */ /* * Fonction exécutée automatiquement toutes les 30 minutes par Jeedom public static function cron30() {} */ /* * Fonction exécutée automatiquement toutes les heures par Jeedom public static function cronHourly() {} */ /* * Fonction exécutée automatiquement tous les jours par Jeedom */ public static function cronDaily() { foreach (self::byType('aps_ecu', true) as $plugin) { $cmd = $plugin->getCmd(null, 'reboot'); if (!is_object($cmd)) { continue; } $cmd->execCmd(); } } /* * *********************Méthodes d'instance************************* */ function open_socket($address, $port) { set_time_limit(30); $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!$socket) { log::add(__CLASS__, 'debug', 'Can\'t create IPv4 TCP socket'); return false; } socket_set_timeout($socket, self::SOCKET_TIMEOUT); socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec" => self::SOCKET_TIMEOUT, "usec" => 0)); socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec" => self::SOCKET_TIMEOUT, "usec" => 0)); //socket_set_option($socket, SOL_SOCKET, SO_LINGER, array('l_linger' => 0, 'l_onoff' => 1)); if (!socket_connect($socket, $address, $port)) { $err = socket_last_error($socket); log::add(__CLASS__, 'debug', 'Can\'t connect to ' . $address . ':' . strval($port) . ' socket err => ' . strval($err)); return false; } return $socket; } function close_socket($socket) { set_time_limit(30); socket_shutdown($socket, 2); socket_recv($socket, $data, self::RECV_BUFFER_LENGTH, 0); socket_close($socket); } function read_socket($socket) { log::add(__CLASS__, 'debug', "Read socket"); $str = ''; $end_data = ''; $data = ''; set_time_limit(30); socket_set_timeout($socket, self::SOCKET_TIMEOUT); $err = socket_recv($socket, $data, self::RECV_BUFFER_LENGTH, 0); if ($err == 0) { log::add(__CLASS__, 'debug', "Read stop size = 0 err => " . strval($err)); return false; } else if ($err === false) { log::add(__CLASS__, 'debug', "Read stop ERROR err => " . strval($err)); return false; } $str = $str . $data; $end_data = substr($data, strlen($data) - 4); return $str; } function write_socket($socket, $data) { $utf8_data = utf8_encode($data); $size_to_write = strlen($utf8_data); $size_written = 0; while ($size_written != $size_to_write) { socket_set_timeout($socket, self::SOCKET_TIMEOUT); $ret = socket_write($socket, substr($utf8_data, $size_written)); if ($ret === false) return false; else $size_written += $ret; } return true; } function check_checksum($data) { $byte_length = strlen($data) - 1; if (substr($data, 0, 3) != 'APS') { log::add(__CLASS__, 'debug', 'Wrong start of packet, dropping packet'); return false; } if (substr($data, $byte_length - 3, 3) != 'END') { log::add(__CLASS__, 'debug', 'Wrong start of packet, dropping packet'); return false; } $checksum = intval(substr($data, 5, 4)); log::add(__CLASS__, 'debug', 'data length: ' . $byte_length); log::add(__CLASS__, 'debug', 'checksum: ' . $checksum); $data_ok = $byte_length == $checksum; if (!$data_ok) { log::add(__CLASS__, 'debug', 'Checksum error, dropping packet'); } return $data_ok; } function aps_str($data, $start, $length) { return substr($data, $start, $length); } function aps_int($data, $offset) { $sub = bin2hex(substr($data, $offset, 2)); return hexdec($sub); } function aps_double($data, $offset) { $sub = bin2hex(substr($data, $offset, 4)); return hexdec($sub); } function aps_uid($data, $offset) { $part = substr($data, $offset, 12); $sub = bin2hex($part); return substr($sub, 0, 12); } function aps_bool($data, $offset) { $sub = bin2hex(substr($data, $offset, 1)); return boolval(hexdec($sub)); } function is_ecu_c($ecu_id) { return substr($ecu_id, 0, 3) == self::END_ECU_C_UID_PREFIX; } public function refresh_ecu_data($ip, $port) { log::add(__CLASS__, 'debug', '--------------------------------------------------'); log::add(__CLASS__, 'debug', 'Refresh ECU DATA: START'); $socket = $this->open_socket($ip, $port); if (!$socket) return false; $command = 'APS1100160001' . self::END_REQUEST_SUFFIX; if (!$this->write_socket($socket, $command)) { $this->close_socket($socket); return false; } $data = $this->read_socket($socket); $this->close_socket($socket); if (!$data || empty($data)) return false; log::add(__CLASS__, 'debug', 'Refresh ECU DATA: ' . $data); log::add(__CLASS__, 'debug', 'Refresh ECU DATA: length data = ' . strval(strlen($data) - 1)); if (!$this->check_checksum($data)) { log::add(__CLASS__, 'debug', 'Refresh ECU DATA: Wrong checksum'); return false; } $result['ecu_id'] = $this->aps_str($data, 13, 12); $result['qty_of_inverters'] = $this->aps_int($data, 46); $result['qty_of_online_inverters'] = $this->aps_int($data, 48); $vsl = intval($this->aps_str($data, 52, 3)); $result['firmware'] = $this->aps_str($data, 55, $vsl); $tsl = intval($this->aps_str($data, 55 + $vsl, 3)); $result['timezone'] = $this->aps_str($data, 58 + $vsl, $tsl); $result['lifetime_energy'] = $this->aps_double($data, 27) / 10; $result['today_energy'] = $this->aps_double($data, 35) / 100; $result['current_power'] = $this->aps_double($data, 31); log::add(__CLASS__, 'debug', 'Refresh ECU DATA: ' . json_encode($result)); log::add(__CLASS__, 'debug', 'Refresh ECU DATA: END'); return $result; } function refresh_inverters($ip, $port, $ecu_id) { log::add(__CLASS__, 'debug', '--------------------------------------------------'); log::add(__CLASS__, 'debug', 'Refresh INVERTERS: START'); $qs1_ids = [ "802", "801", "804", "805", "806" ]; $yc600_ids = [ "406", "407", "408", "409" ]; $yc1000_ids = [ "501", "502", "503", "504" ]; $ds3_ids = [ "703", "704", "705" ]; $socket = $this->open_socket($ip, $port); if (!$socket) return false; $command = 'APS1100280002' . $ecu_id . self::END_REQUEST_SUFFIX; if (!$this->write_socket($socket, $command)) { $this->close_socket($socket); return false; } sleep(self::SLEEP_DELAY); $data = $this->read_socket($socket); $this->close_socket($socket); if ($data === false || empty($data)) return false; log::add(__CLASS__, 'debug', 'Refresh INVERTERS: ' . $data); log::add(__CLASS__, 'debug', 'Refresh INVERTERS: length data = ' . strval(strlen($data) - 1)); if (!$this->check_checksum($data)) return false; // Seems not OK, disable /*$ok = intval(substr($data, 13, 2)); log::add(__CLASS__, 'debug', 'Refresh INVERTERS: No Data ? => ' . strval($ok)); if ($ok != 0) { log::add(__CLASS__, 'debug', 'Refresh INVERTERS: No data marked in packet'); return false; }*/ //$timestamp = $this->aps_timestamp($data, 19, 14); $result = []; $inverter_qty = $this->aps_int($data, 17); $result['inverter_qty'] = $inverter_qty; $location = 26; // Not enough data, wrong packet ?!! if ($location >= strlen($data)) { log::add(__CLASS__, 'debug', 'Refresh INVERTERS: Not enough data in packet => return no data'); return []; } for ($i = 0; $i < $inverter_qty; $i++) { $inverter_uid = $this->aps_uid($data, $location); $result[$i]["uid"] = $inverter_uid; $location += 6; $online = $this->aps_bool($data, $location); $result[$i]["online"] = $online; $location += 1; // Unknown $location += 2; $frequency = $this->aps_int($data, $location) / 10.0; $result[$i]["frequency"] = $frequency; $location += 2; $temperature = $this->aps_int($data, $location) - 100.0; $result[$i]["temperature"] = $temperature; $location += 2; $inverter_type = substr($inverter_uid, 0, 3); $channel_count = 0; if (in_array($inverter_type, $yc600_ids)) { $channel_count = 2; $result[$i]["model"] = "YC600"; $result[$i]["channel_count"] = $channel_count; for ($c = 0; $c < $channel_count; $c++) { $power[$c] = $this->aps_int($data, $location); $result[$i]["power"][$c] = $power[$c]; $location += 2; $voltage[$c] = $this->aps_int($data, $location); $result[$i]["voltage"][$c] = $voltage[$c]; $location += 2; } } else if (in_array($inverter_type, $qs1_ids)) { $channel_count = 4; $result[$i]["model"] = "QS1"; $result[$i]["channel_count"] = $channel_count; $power[0] = $this->aps_int($data, $location); $location += 2; $voltage[0] = $this->aps_int($data, $location); $location += 2; $power[1] = $this->aps_int($data, $location); $location += 2; $power[2] = $this->aps_int($data, $location); $location += 2; $power[3] = $this->aps_int($data, $location); $location += 2; $result[$i]["voltage"] = $voltage; $result[$i]["power"] = $power; } else if (in_array($inverter_type, $yc1000_ids)) { $channel_count = 4; $result[$i]["model"] = "YC1000"; $result[$i]["channel_count"] = $channel_count; $power[0] = $this->aps_int($data, $location); $location += 2; $voltage[0] = $this->aps_int($data, $location); $location += 2; $power[1] = $this->aps_int($data, $location); $location += 2; $voltage[1] = $this->aps_int($data, $location); $location += 2; $power[2] = $this->aps_int($data, $location); $location += 2; $voltage[2] = $this->aps_int($data, $location); $location += 2; $power[3] = $this->aps_int($data, $location); $location += 2; $result[$i]["voltage"] = $voltage; $result[$i]["power"] = $power; } else if (in_array($inverter_type, $qt2_ids)) { $channel_count = 4; $result[$i]["model"] = "QT2"; $result[$i]["channel_count"] = $channel_count; $power[0] = $this->aps_int($data, $location); $location += 2; $voltage[0] = $this->aps_int($data, $location); $location += 2; $power[1] = $this->aps_int($data, $location); $location += 2; $voltage[1] = $this->aps_int($data, $location); $location += 2; $power[2] = $this->aps_int($data, $location); $location += 2; $voltage[2] = $this->aps_int($data, $location); $location += 2; $power[3] = $this->aps_int($data, $location); $location += 2; $result[$i]["voltage"] = $voltage; $result[$i]["power"] = $power; } else if (in_array($inverter_type, $ds3_ids)) { $channel_count = 2; $result[$i]["model"] = "DS3"; $result[$i]["channel_count"] = $channel_count; for ($c = 0; $c < $channel_count; $c++) { $power[$c] = $this->aps_int($data, $location); $location += 2; $voltage[$c] = $this->aps_int($data, $location); $location += 2; } $result[$i]["voltage"] = $voltage; $result[$i]["power"] = $power; } else return false; } log::add(__CLASS__, 'debug', 'Refresh INVERTERS: ' . json_encode($result)); log::add(__CLASS__, 'debug', 'Refresh INVERTERS: END'); return $result; } public function query_inverter_signal($ip, $port, $ecu_id, $inverter_qty) { log::add(__CLASS__, 'debug', '--------------------------------------------------'); log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: START'); $socket = $this->open_socket($ip, $port); if (!$socket) return false; $command = 'APS1100280030' . $ecu_id . self::END_REQUEST_SUFFIX; if (!$this->write_socket($socket, $command)) { $this->close_socket($socket); return false; } sleep(self::SLEEP_DELAY); $data = $this->read_socket($socket); $this->close_socket($socket); if ($data === false || empty($data)) return false; log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: ' . $data); log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: length data = ' . strval(strlen($data) - 1)); if (!$this->check_checksum($data)) return false; // Seems not OK, disable //$ok = intval(substr($data, 13, 2)); //log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: No Data ? => ' . strval($ok)); //if ($ok != 0) //{ // log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: No data marked in packet'); // return false; //} $location = 15; $signal_data = []; for ($i = 0; $i < $inverter_qty; $i++) { $uid = $this->aps_uid($data, $location); $location += 6; $strength = unpack("C", substr($data, $location, 1))[1]; $location += 1; $strength = intval(($strength / 255.0) * 100.0); $signal_data[$uid] = $strength; } log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: ' . json_encode($signal_data)); log::add(__CLASS__, 'debug', 'Refresh INVERTERS SIGNAL: END'); return $signal_data; } function get_power_of_day($ip, $ecu_id, $date) { $url = 'http://' . $ip . '/index.php/hidden/set_get_app_info_json'; $reqbody = utf8_encode( '{"Command_Id": "53", "APS": "ASK", "date_time": "' . $date . '", "Command": "1", "VERSION": "1.1", "ECUID": "' . $ecu_id . '"}' ); $options = array( 'http' => array( 'header' => "Content-type: application/json;charset=utf-8\r\n", 'method' => 'POST', 'content' => $reqbody ) ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if (!$result) return false; return json_decode($result, true); } function reboot_ecu() { log::add(__CLASS__, 'debug', 'Rebooting ECU...'); $ip = $this->getConfiguration("ecu_ip", ""); $ssid = $this->getConfiguration("lwa_ssid", ""); $channel = $this->getConfiguration("lwa_channel", "0"); $encryption = $this->getConfiguration("lwa_encryption", "0"); $password = $this->getConfiguration("lwa_password", ""); $url = 'http://' . $ip . '/index.php/management/set_wlan_ap'; $data = array('SSID' => $ssid, 'channel' => $channel, 'method' => $encryption, 'psk_wep' => $password, 'psk_wpa' => $password ); $options = array( 'http' => array( 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => http_build_query($data) ) ); $context = stream_context_create($options); $result = file_get_contents($url, false, $context); if ($result === false) { log::add(__CLASS__, 'debug', 'Error during ECU reboot'); } } // Fonction exécutée automatiquement avant la création de l'équipement public function preInsert() { } // Fonction exécutée automatiquement après la création de l'équipement public function postInsert() { } // Fonction exécutée automatiquement avant la mise à jour de l'équipement public function preUpdate() { } // Fonction exécutée automatiquement après la mise à jour de l'équipement public function postUpdate() { // Create dynamic inverter commands $ip = $this->getConfiguration("ecu_ip", ""); $port = $this->getConfiguration("ecu_port", "8899"); if(empty($ip)) { throw new Exception(__('L\'IP locale de l\'ECU est vide. Renseignez là avant de sauvegarder.', __FILE__)); return; } $result_ecu = $this->refresh_ecu_data($ip, intval($port)); if ($result_ecu === false) { throw new Exception(__('Impossible de se connecter à l\'ECU. Vérifiez l\'IP et le port.', __FILE__)); return; } //sleep(1); $result_inverters = $this->refresh_inverters($ip, intval($port), $result_ecu['ecu_id']); if ($result_inverters === false) { throw new Exception(__('Impossible de se connecter à l\'ECU. Vérifiez l\'IP et le port.', __FILE__)); return; } $order = 0; $lifetime_energy = $this->getCmd(null, 'lifetime_energy'); if (!is_object($lifetime_energy)) { $lifetime_energy = new aps_ecuCmd(); $lifetime_energy->setTemplate('dashboard','tile'); $lifetime_energy->setIsHistorized(true); $lifetime_energy->setOrder($order++); $lifetime_energy->setDisplay('parameters', array( 'forceReturnLineBefore' => true )); } $lifetime_energy->setName(__('Energie Totale', __FILE__)); $lifetime_energy->setLogicalId('lifetime_energy'); $lifetime_energy->setEqLogic_id($this->getId()); $lifetime_energy->setType('info'); $lifetime_energy->setUnite('kWh'); $lifetime_energy->setSubType('numeric'); $lifetime_energy->SetValue($result_ecu['lifetime_energy']); $lifetime_energy->save(); $current_day_energy = $this->getCmd(null, 'current_day_energy'); if (!is_object($current_day_energy)) { $current_day_energy = new aps_ecuCmd(); $current_day_energy->setTemplate('dashboard','tile'); $current_day_energy->setIsHistorized(true); $current_day_energy->setOrder($order++); } $current_day_energy->setName(__('Energie Aujourd\'hui', __FILE__)); $current_day_energy->setLogicalId('current_day_energy'); $current_day_energy->setEqLogic_id($this->getId()); $current_day_energy->setType('info'); $current_day_energy->setUnite('kWh'); $current_day_energy->setSubType('numeric'); $current_day_energy->SetValue($result_ecu['today_energy']); $current_day_energy->save(); if ($this->is_ecu_c($result_ecu['ecu_id'])) { $date = date('Y-m-d'); //sleep(1); $json = $this->get_power_of_day($ip, $result_ecu['ecu_id'], $date); if ($json) { if (array_key_exists('meter_data', $json)) { $meter_data = $json["meter_data"]; if (array_key_exists('power2', $meter_data)) { $imported_power_info = $this->getCmd(null, 'imported_power_a'); if (!is_object($imported_power_info)) { $imported_power_info = new aps_ecuCmd(); $imported_power_info->setTemplate('dashboard','tile'); $imported_power_info->setIsHistorized(true); $imported_power_info->setOrder($order++); } $imported_power_info->setName(__('Puissance Importée Courante _1', __FILE__)); $imported_power_info->setLogicalId('imported_power_a'); $imported_power_info->setEqLogic_id($this->getId()); $imported_power_info->setType('info'); $imported_power_info->setUnite('W'); $imported_power_info->setSubType('numeric'); $imported_power_info->save(); $imported_power_info = $this->getCmd(null, 'imported_power_b'); if (!is_object($imported_power_info)) { $imported_power_info = new aps_ecuCmd(); $imported_power_info->setTemplate('dashboard','tile'); $imported_power_info->setIsHistorized(true); $imported_power_info->setOrder($order++); } $imported_power_info->setName(__('Puissance Importée Courante _2', __FILE__)); $imported_power_info->setLogicalId('imported_power_b'); $imported_power_info->setEqLogic_id($this->getId()); $imported_power_info->setType('info'); $imported_power_info->setUnite('W'); $imported_power_info->setSubType('numeric'); $imported_power_info->save(); $imported_power_info = $this->getCmd(null, 'imported_power_c'); if (!is_object($imported_power_info)) { $imported_power_info = new aps_ecuCmd(); $imported_power_info->setTemplate('dashboard','tile'); $imported_power_info->setIsHistorized(true); $imported_power_info->setOrder($order++); } $imported_power_info->setName(__('Puissance Importée Courante _3', __FILE__)); $imported_power_info->setLogicalId('imported_power_c'); $imported_power_info->setEqLogic_id($this->getId()); $imported_power_info->setType('info'); $imported_power_info->setUnite('W'); $imported_power_info->setSubType('numeric'); $imported_power_info->save(); $values_count = count($meter_data['power2']); if ($values_count > 0) { $entry = $meter_data['power2'][$values_count - 1]; $time = $entry['time']; $year = substr($time, 0, 4); $month = substr($time, 4, 2); $day = substr($time, 6, 2); $hour = substr($time, 8, 2); $minute = substr($time, 10, 2); $second = substr($time, 12, 2); $power_a = $entry['powerA']; $power_b = $entry['powerB']; $power_c = $entry['powerC']; $this->checkAndUpdateCmd('imported_power_a', $last_imported_power); $this->checkAndUpdateCmd('imported_power_b', $last_imported_power); $this->checkAndUpdateCmd('imported_power_c', $last_imported_power); } } } } $self_consumption_info = $this->getCmd(null, 'self_consumption'); if (!is_object($self_consumption_info)) { $self_consumption_info = new aps_ecuCmd(); $self_consumption_info->setTemplate('dashboard','tile'); $self_consumption_info->setIsHistorized(true); $self_consumption_info->setOrder($order++); $self_consumption_info->setType('info'); $self_consumption_info->setUnite('%'); $self_consumption_info->setSubType('numeric'); } $self_consumption_info->setName(__('Auto-Consommation', __FILE__)); $self_consumption_info->setLogicalId('self_consumption'); $self_consumption_info->setEqLogic_id($this->getId()); $self_consumption_info->save(); } $current_power_info = $this->getCmd(null, 'current_power'); if (!is_object($current_power_info)) { $current_power_info = new aps_ecuCmd(); $current_power_info->setTemplate('dashboard','tile'); $current_power_info->setIsHistorized(true); $current_power_info->setOrder($order++); $current_power_info->setDisplay('parameters', array( 'forceReturnLineAfter' => true )); } $current_power_info->setName(__('Puissance Courante', __FILE__)); $current_power_info->setLogicalId('current_power'); $current_power_info->setEqLogic_id($this->getId()); $current_power_info->setType('info'); $current_power_info->setUnite('W'); $current_power_info->setSubType('numeric'); $current_power_info->SetValue($result_ecu['current_power']); $current_power_info->save(); $refresh = $this->getCmd(null, 'refresh'); if (!is_object($refresh)) { $refresh = new aps_ecuCmd(); } $refresh->setName(__('Refresh', __FILE__)); $refresh->setEqLogic_id($this->getId()); $refresh->setLogicalId('refresh'); $refresh->setType('action'); $refresh->setSubType('other'); $refresh->save(); $reboot = $this->getCmd(null, 'reboot'); if (!is_object($reboot)) { $reboot = new aps_ecuCmd(); } $reboot->setName(__('Reboot', __FILE__)); $reboot->setEqLogic_id($this->getId()); $reboot->setLogicalId('reboot'); $reboot->setType('action'); $reboot->setSubType('other'); $reboot->save(); for ($i = 0; $i < $result_inverters['inverter_qty']; $i++) { $invert_uid = $result_inverters[$i]['uid']; if (!$invert_uid || strlen($invert_uid) == 0) break; /*$inverter_uid_cmd = $this->getCmd(null, 'inverter_uid_' . $invert_uid ); if (!is_object($inverter_uid_cmd)) { $inverter_uid_cmd = new aps_ecuCmd(); } $inverter_uid_cmd->setName(__('Inverter ' . $invert_uid, __FILE__)); $inverter_uid_cmd->setLogicalId('inverter_uid_' . $invert_uid); $inverter_uid_cmd->setEqLogic_id($this->getId()); $inverter_uid_cmd->setType('info'); $inverter_uid_cmd->setSubType('string'); $inverter_uid_cmd->setTemplate('dashboard','tile'); $inverter_uid_cmd->save();*/ $inverter_online_cmd = $this->getCmd(null, 'inverter_online_uid_' . $invert_uid); if (!is_object($inverter_online_cmd)) { $inverter_online_cmd = new aps_ecuCmd(); $inverter_online_cmd->setTemplate('dashboard','aps_ecu::online'); $inverter_online_cmd->setDisplay('forceReturnLineBefore', '1' ); } $inverter_online_cmd->setName($invert_uid . __(' En Ligne', __FILE__)); $inverter_online_cmd->setLogicalId('inverter_online_uid_' . $invert_uid); $inverter_online_cmd->setEqLogic_id($this->getId()); $inverter_online_cmd->setType('info'); $inverter_online_cmd->setSubType('binary'); $inverter_online_cmd->setOrder($order++); $inverter_online_cmd->save(); $inverter_frequency_cmd = $this->getCmd(null, 'inverter_frequency_uid_' . $invert_uid); if (!is_object($inverter_frequency_cmd)) { $inverter_frequency_cmd = new aps_ecuCmd(); $inverter_frequency_cmd->setTemplate('dashboard','aps_ecu::text'); $inverter_frequency_cmd->setConfiguration('minValue', 47.5); $inverter_frequency_cmd->setConfiguration('maxValue', 51.5); $inverter_frequency_cmd->setDisplay('parameters', array ( 'ref_milieu' => '1', 'couleurfr' => '\#86e01e' )); $inverter_frequency_cmd->setIsHistorized(true); } $inverter_frequency_cmd->setName($invert_uid . __(' Fréquence', __FILE__)); $inverter_frequency_cmd->setLogicalId('inverter_frequency_uid_' . $invert_uid); $inverter_frequency_cmd->setEqLogic_id($this->getId()); $inverter_frequency_cmd->setType('info'); $inverter_frequency_cmd->setSubType('numeric'); $inverter_frequency_cmd->setUnite('Hz'); $inverter_frequency_cmd->setOrder($order++); $inverter_frequency_cmd->save(); $inverter_temperature_cmd = $this->getCmd(null, 'inverter_temperature_uid_' . $invert_uid); if (!is_object($inverter_temperature_cmd)) { $inverter_temperature_cmd = new aps_ecuCmd(); $inverter_temperature_cmd->setTemplate('dashboard','text'); $inverter_temperature_cmd->setIsHistorized(true); $inverter_temperature_cmd->setConfiguration('minValue', 0); $inverter_temperature_cmd->setConfiguration('maxValue', 100); $inverter_frequency_cmd->setDisplay('parameters', array ( 'ref_milieu' => '1' )); } $inverter_temperature_cmd->setName($invert_uid . __(' Température', __FILE__)); $inverter_temperature_cmd->setLogicalId('inverter_temperature_uid_' . $invert_uid); $inverter_temperature_cmd->setEqLogic_id($this->getId()); $inverter_temperature_cmd->setType('info'); $inverter_temperature_cmd->setSubType('numeric'); $inverter_temperature_cmd->setUnite('°C'); $inverter_temperature_cmd->setOrder($order++); $inverter_temperature_cmd->save(); $inverter_signal_cmd = $this->getCmd(null, 'inverter_signal_uid_' . $invert_uid); if (!is_object($inverter_signal_cmd)) { $inverter_signal_cmd = new aps_ecuCmd(); $inverter_signal_cmd->setTemplate('dashboard','aps_ecu::text'); $inverter_signal_cmd->setConfiguration('minValue', 0); $inverter_signal_cmd->setConfiguration('maxValue', 100); $inverter_signal_cmd->setDisplay('parameters', array ( 'couleurfr' => '\#fc0303', 'couleurch' => '\#86e01e' )); $inverter_signal_cmd->setIsHistorized(true); } $inverter_signal_cmd->setName($invert_uid . __(' Signal Radio', __FILE__)); $inverter_signal_cmd->setLogicalId('inverter_signal_uid_' . $invert_uid); $inverter_signal_cmd->setEqLogic_id($this->getId()); $inverter_signal_cmd->setType('info'); $inverter_signal_cmd->setSubType('numeric'); $inverter_signal_cmd->setUnite('%'); $inverter_signal_cmd->setOrder($order++); $inverter_signal_cmd->save(); $inverter_power_cmd = $this->getCmd(null, 'inverter_power_uid_' . $invert_uid); if (!is_object($inverter_power_cmd)) { $inverter_power_cmd = new aps_ecuCmd(); $inverter_power_cmd->setTemplate('dashboard','aps_ecu::progress_bar'); $inverter_power_cmd->setIsHistorized(true); $inverter_power_cmd->setConfiguration('minValue', 0); } $inverter_power_cmd->setName($invert_uid . __(' Puissance Totale', __FILE__)); $inverter_power_cmd->setLogicalId('inverter_power_uid_' . $invert_uid); $inverter_power_cmd->setEqLogic_id($this->getId()); $inverter_power_cmd->setType('info'); $inverter_power_cmd->setSubType('numeric'); $inverter_power_cmd->setUnite('W'); $inverter_power_cmd->setOrder($order++); $inverter_power_cmd->save(); foreach ($result_inverters[$i]['power'] as $key => $value) { $inverter_channel_power_cmd = $this->getCmd(null, 'inverter_power_uid_' . $invert_uid . '_channel_' . strval($key)); if (!is_object($inverter_channel_power_cmd)) { $inverter_channel_power_cmd = new aps_ecuCmd(); $inverter_channel_power_cmd->setIsHistorized(true); $inverter_channel_power_cmd->setTemplate('dashboard','aps_ecu::progress_bar'); $inverter_channel_power_cmd->setDisplay('parameters', array ( 'type' => 'vertical' ) ); $inverter_channel_power_cmd->setConfiguration('minValue', 0); } $inverter_channel_power_cmd->setName($invert_uid . '-' . strval($key + 1) . __(' Puissance', __FILE__)); $inverter_channel_power_cmd->setLogicalId('inverter_power_uid_' . $invert_uid . '_channel_' . strval($key)); $inverter_channel_power_cmd->setEqLogic_id($this->getId()); $inverter_channel_power_cmd->setType('info'); $inverter_channel_power_cmd->setSubType('numeric'); $inverter_channel_power_cmd->setUnite('W'); $inverter_channel_power_cmd->setOrder($order++); $inverter_channel_power_cmd->save(); } foreach ($result_inverters[$i]['voltage'] as $key => $value) { $inverter_channel_voltage_cmd = $this->getCmd(null, 'inverter_voltage_uid_' . $invert_uid . '_channel_' . strval($key)); if (!is_object($inverter_channel_voltage_cmd)) { $inverter_channel_voltage_cmd = new aps_ecuCmd(); $inverter_channel_voltage_cmd->setIsHistorized(true); $inverter_channel_voltage_cmd->setConfiguration('minValue', 207); $inverter_channel_voltage_cmd->setConfiguration('maxValue', 253); $inverter_channel_voltage_cmd->setTemplate('dashboard','aps_ecu::text'); $inverter_channel_voltage_cmd->setDisplay('parameters', array ( 'ref_milieu' => '1', 'couleurfr' => '\#86e01e' ) ); } $inverter_channel_voltage_cmd->setName($invert_uid . '-' . strval($key + 1) . __(' Tension', __FILE__)); $inverter_channel_voltage_cmd->setLogicalId('inverter_voltage_uid_' . $invert_uid . '_channel_' . strval($key)); $inverter_channel_voltage_cmd->setEqLogic_id($this->getId()); $inverter_channel_voltage_cmd->setType('info'); $inverter_channel_voltage_cmd->setSubType('numeric'); $inverter_channel_voltage_cmd->setUnite('V'); $inverter_channel_voltage_cmd->setOrder($order++); $inverter_channel_voltage_cmd->save(); } } } // Fonction exécutée automatiquement avant la sauvegarde (création ou mise à jour) de l'équipement public function preSave() { } // Fonction exécutée automatiquement après la sauvegarde (création ou mise à jour) de l'équipement public function postSave() { } // Fonction exécutée automatiquement avant la suppression de l'équipement public function preRemove() { } // Fonction exécutée automatiquement après la suppression de l'équipement public function postRemove() { } /* * Permet de crypter/décrypter automatiquement des champs de configuration des équipements * Exemple avec le champ "Mot de passe" (password) public function decrypt() { $this->setConfiguration('password', utils::decrypt($this->getConfiguration('password'))); } public function encrypt() { $this->setConfiguration('password', utils::encrypt($this->getConfiguration('password'))); } */ /* * Permet de modifier l'affichage du widget (également utilisable par les commandes) */ /*public function toHtml($_version = 'dashboard') { if ($this->getConfiguration('widgetTemplate') != 1) { return parent::toHtml($_version); } $replace = $this->preToHtml($_version); if (!is_array($replace)) { return $replace; } $version = jeedom::versionAlias($_version); foreach (($this->getCmd('info')) as $cmd) { $logical = $cmd->getLogicalId(); $collectDate = $cmd->getCollectDate(); $expectedCollectDate = (in_array($logical, ['consumption_load_curve', 'production_load_curve'])) ? date('Y-m-d') : date('Y-m-d', strtotime('-1 day')); $replace['#' . $logical . '_id#'] = $cmd->getId(); $replace['#' . $logical . '#'] = $cmd->execCmd(); $replace['#' . $logical . '_unite#'] = $cmd->getUnite(); $replace['#' . $logical . '_collect#'] = $collectDate; $replace['#' . $logical . '_toDate#'] = ($collectDate >= $expectedCollectDate) ? 1 : 0; } $replace['#refresh_id#'] = $this->getCmd('action', 'refresh')->getId(); $replace['#BGEnedis#'] = ($this->getConfiguration('widgetTransparent') == 1) ? 'transparent' : $this->getConfiguration('widgetBGColor'); $replace['#measureType#'] = $this->getConfiguration('measure_type'); $html = template_replace($replace, getTemplate('core', $version, 'aps_ecu.template', __CLASS__)); cache::set('widgetHtml' . $_version . $this->getId(), $html, 0); return $html; }*/ /* * Permet de déclencher une action avant modification d'une variable de configuration du plugin * Exemple avec la variable "param3" public static function preConfig_param3( $value ) { // do some checks or modify on $value return $value; } */ /* * Permet de déclencher une action après modification d'une variable de configuration du plugin * Exemple avec la variable "param3" public static function postConfig_param3($value) { // no return value } */ /* * **********************Getteur Setteur*************************** */ } class aps_ecuCmd extends cmd { /* * *************************Attributs****************************** */ /* public static $_widgetPossibility = array(); */ /* * ***********************Methode static*************************** */ /* * *********************Methode d'instance************************* */ /* * Permet d'empêcher la suppression des commandes même si elles ne sont pas dans la nouvelle configuration de l'équipement envoyé en JS public function dontRemoveCmd() { return true; } */ function refreshData() { $eqlogic = $this->getEqLogic(); $ip = $eqlogic->getConfiguration("ecu_ip", ""); $port = $eqlogic->getConfiguration("ecu_port", "8899"); if (empty($ip)) return; // Update ECU global commands $result_ecu = $eqlogic->refresh_ecu_data($ip, intval($port)); if ($result_ecu === false) // Can't continue, we do not have ECU UID return; $eqlogic->checkAndUpdateCmd('lifetime_energy', $result_ecu['lifetime_energy']); $eqlogic->checkAndUpdateCmd('current_day_energy', $result_ecu['today_energy']); $eqlogic->checkAndUpdateCmd('current_power', $result_ecu['current_power']); // Get and update inverters commands // if ($result_ecu['qty_of_online_inverters'] != 0) { $result_inverters = $eqlogic->refresh_inverters($ip, intval($port), $result_ecu['ecu_id']); if (!($result_inverters === false)) { for ($i = 0; $i < $result_inverters['inverter_qty']; $i++) { $invert_uid = $result_inverters[$i]['uid']; $eqlogic->checkAndUpdateCmd('inverter_online_uid_' . $invert_uid , $result_inverters[$i]['online']); if ($result_inverters[$i]['online']) { $eqlogic->checkAndUpdateCmd('inverter_frequency_uid_' . $invert_uid , $result_inverters[$i]['frequency']); $eqlogic->checkAndUpdateCmd('inverter_temperature_uid_' . $invert_uid , $result_inverters[$i]['temperature']); $power = 0; for ($c = 0; $c < $result_inverters[$i]['channel_count']; $c++) $power += $result_inverters[$i]["power"][$c]; $eqlogic->checkAndUpdateCmd('inverter_power_uid_' . $invert_uid , $power); foreach ($result_inverters[$i]['power'] as $key => $value) { $invert_uid = $result_inverters[$i]['uid']; $eqlogic->checkAndUpdateCmd('inverter_online_uid_' . $invert_uid , $result_inverters[$i]['online']); if ($result_inverters[$i]['online']) { $eqlogic->checkAndUpdateCmd('inverter_frequency_uid_' . $invert_uid , $result_inverters[$i]['frequency']); $eqlogic->checkAndUpdateCmd('inverter_temperature_uid_' . $invert_uid , $result_inverters[$i]['temperature']); $power = 0; for ($c = 0; $c < $result_inverters[$i]['channel_count']; $c++) $power += $result_inverters[$i]["power"][$c]; $eqlogic->checkAndUpdateCmd('inverter_power_uid_' . $invert_uid , $power); foreach ($result_inverters[$i]['power'] as $key => $value) { $eqlogic->checkAndUpdateCmd('inverter_power_uid_' . $invert_uid . '_channel_' . strval($key), $value); } foreach ($result_inverters[$i]['voltage'] as $key => $value) { $eqlogic->checkAndUpdateCmd('inverter_voltage_uid_' . $invert_uid . '_channel_' . strval($key), $value); } } } // Get and update inverters signal $result_inverters_signals = $eqlogic->query_inverter_signal($ip, intval($port), $result_ecu['ecu_id'], $result_inverters['inverter_qty']); if (!($result_inverters_signals === false)) { foreach ($result_inverters_signals as $uid => $value) $eqlogic->checkAndUpdateCmd('inverter_signal_uid_' . $uid , $value); } } } // Get and update inverters signal $result_inverters_signals = $eqlogic->query_inverter_signal($ip, intval($port), $result_ecu['ecu_id'], $result_inverters['inverter_qty']); if (!($result_inverters_signals === false)) { foreach ($result_inverters_signals as $uid => $value) $eqlogic->checkAndUpdateCmd('inverter_signal_uid_' . $uid , $value); } } } // Imported Power if ($eqlogic->is_ecu_c($result_ecu['ecu_id'])) { $date = date('Y-m-d'); $json = $eqlogic->get_power_of_day($ip, $result_ecu['ecu_id'], $date); if ($json) { if (array_key_exists('meter_data', $json)) { $meter_data = $json["meter_data"]; if (array_key_exists('power2', $meter_data)) { $values_count = count($meter_data['power2']); if ($values_count > 0) { // Imported $entry = $meter_data['power2'][$values_count - 1]; $time = $entry['time']; $year = substr($time, 0, 4); $month = substr($time, 4, 2); $day = substr($time, 6, 2); $hour = substr($time, 8, 2); $minute = substr($time, 10, 2); $second = substr($time, 12, 2); $power_a = $entry['powerA']; $power_b = $entry['powerB']; $power_c = $entry['powerC']; $eqlogic->checkAndUpdateCmd('imported_power_a', $power_a); $eqlogic->checkAndUpdateCmd('imported_power_b', $power_b); $eqlogic->checkAndUpdateCmd('imported_power_c', $power_c); // Produced if (array_key_exists('power1', $meter_data) && count($meter_data['power1']) == count($meter_data['power2'])) { $total_produced = 0; $total_consumed = 0; for ($i = 0; $i < $values_count; $i++) { $produced = $meter_data['power1'][$i]['powerA']; $imported = $meter_data['power2'][$i]['powerA']; $total_produced += $produced; $consumed = $produced + $imported; $total_consumed += min($consumed, $produced); } $self_consumption = floatval($total_consumed) / floatval($total_produced) * 100.0; $eqlogic->checkAndUpdateCmd('self_consumption', $self_consumption); } } } } } } } // Exécution d'une commande public function execute($_options = array()) { log::add(__CLASS__, 'debug', 'command -> '); switch ($this->getLogicalId()) { case 'refresh': { $this->refreshData(); } break; case 'reboot': { $eqlogic = $this->getEqLogic(); $restart = $eqlogic->getConfiguration("ecu_restart", false); if ($restart) { $eqlogic->reboot_ecu(); } } break; } } /* * **********************Getteur Setteur*************************** */ }