/** * parse data from device * @param array $packet * @return array */ private function parse_switch($packet) { $this->debug(__FUNCTION__, 'Parse'); $l = count($packet); if ($l != 8) { $this->debug(__FUNCTION__, 'Length wrong:' . $l . '<->8'); return false; } //if len //FS20 02 06 A2 HH HH HH AA EE $src = $packet[3] . $packet[4] . $packet[5]; $fs20data = $packet[6] . $packet[7]; $hc = FHZ_helper::bin2four($src); //prepare structure $data = array(); $data['Typ'] = 'FS20'; //Device FS20 $data['DeviceID'] = $hc; // $data['FS20'] = utf8_encode($fs20data); $data['Class'] = __CLASS__; $action = FHZ_helper::$fs20_codes[strToHex($fs20data[0])]; if (ord($fs20data[0]) > 31) { $action .= ' Timer:' . FHZ_helper::fs20_times(ord($fs20data[1])); } $text = sprintf('Device:%s(%s), Action:%s (%s)', $hc, strToHex($src), $action, strToHex($fs20data)); $this->debug(__FUNCTION__, $text); $this->SendSwitchData($data); return true; }
/** * handle incoming data along capabilities * @param array $data */ private function ParseData($data) { // $caps = $this->GetCaps(); //$this->debug(__FUNCTION__,print_r($this->all_caps,true)); foreach (array_keys($caps) as $cap) { $ident = $caps[$cap]; $vid = @$this->GetIDForIdent($ident); if ($vid == 0) { $this->debug(__FUNCTION__, "Cap {$cap} Ident {$ident}: Variable missed"); continue; } if (!isset($data[$cap])) { continue; } $s = $data[$cap]; switch ($cap) { //integer case 'TS': //Timestamp //Timestamp case 'Signal': //RSSI //RSSI case 'Timer': //Duration code //Duration code case 'Dimmer': //intensity 100% //intensity 100% case 'Shutter': //intensity 100% $iv = (int) $s; SetValueInteger($vid, $iv); break; //String //String case 'Name': //Duration code $st = utf8_decode($s); SetValueString($vid, $st); break; //special //special case 'Switch': //Status $state = $this->SwitchStatus($s); SetValueBoolean($vid, $state); break; case 'Lock': //Status $state = preg_match("/YES|CLOSE|OK/i", $s); //reversed SetValueBoolean($vid, $state); break; case 'Alert': //Status $state = !preg_match("/YES|ALERT/i", $s); //reversed SetValueBoolean($vid, $state); break; case 'Battery': //battery $state = !preg_match("/LOW|WARN/i", $s); //reversed SetValueBoolean($vid, $state); break; case 'FS20': //fs20 mode decoding $state = false; $intensity = 0; $timer = 0; $acode = ''; $actioncode = ''; $code = utf8_decode($s); $this->debug(__FUNCTION__, "FS20 Code " . strToHex($code)); $action = $code[0]; $ext = ord($code[1]); $tvid = @$this->GetIDForIdent($caps['Timer']); $dvid = @$this->GetIDForIdent($caps['Dimmer']); $swid = @$this->GetIDForIdent($caps['Switch']); $avid = @$this->GetIDForIdent($caps['TimerActionCode']); $this->debug(__FUNCTION__, "FS20 Vars S:{$swid},D:{$dvid},T:{$tvid},A:{$avid}"); if ($dvid) { $intensity = GetValueInteger($dvid); } if ($swid) { $state = GetValueBoolean($swid); } if ($tvid) { $timer = GetValueInteger($tvid); } if ($avid) { $acode = GetValueString($avid); } $ac = ord($action) & 0x1f; $timed = ($action & 0x20) > 0; $this->debug(__FUNCTION__, "FS20 AC:" . $ac . "PrevD:{$intensity}, PrevS:" . ($state ? "On" : "Off")); switch ($ac) { case 0: //off if ($timed) { $actioncode = 'Switch:Off'; } else { $state = false; } break; case $ac < 0xf: //Dim to value $intensity = FHZ_helper::fs20_intensity_percent($action & 0xf); $state = true; if ($timed) { $actioncode = 'Switch:Off'; } break; case 0x10: //on full $state = true; $intensity = 100; if ($timed) { $actioncode = 'Switch:Off'; } break; case 0x11: //on with old value $state = true; if ($intensity == 0) { $intensity = 100; } if ($timed) { $actioncode = 'Switch:Off'; } break; case 0x12: $state = !GetValueBoolean($swid); //toggle break; case 0x13: //dimup $steps = FHZ_helper::fs20_intensity_steps($intensity); $intensity = FHZ_helper::fs20_intensity_percent($steps + 1); $state = true; break; case 0x14: //dimdown if ($intensity == 0) { $intensity = 100; } $steps = FHZ_helper::fs20_intensity_steps($intensity); $intensity = FHZ_helper::fs20_intensity_percent($steps - 1); if ($intensity == 0) { $state = false; } break; case 0x18: //off-for-timer $state = 'Off'; $actioncode = 'Switch:On'; break; case 0x19: //on-for-timer than out $state = true; $actioncode = 'Switch:Off'; break; case 0x1a: //on-old-for-timer than out $state = true; $actioncode = 'Switch:Off'; break; case 0x1c: //ramp-on-time (time to reach the desired dim value on dimmers) $state = true; $actioncode = "Dimmer:{$intensity}"; break; case 0x1d: //ramp-off-time (time to reach the off state on dimmers) $actioncode = 'Switch:Off;Dimmer:0'; break; case 0x1e: //on-old-for-timer-prev", // old val for timer, then go to prev. state $actioncode = "Switch:" . ($state ? 'On' : 'Off'); $state = true; break; case 0x1f: //on-100-for-timer-prev", // 100% for timer, then go to previous state //new intensity will be the old one $action = "Switch:" . ($state ? 'On' : 'Off') . ";Dimmer:{$intensity}"; $intensity = 100; $state = true; break; case 0x15: //dimupdown, no value changes //dimupdown, no value changes case 0x16: //Set Timer //Set Timer case 0x17: //nop //nop case 0x1b: //rese break; } $new_timer = FHZ_helper::fs20_times($ext); $this->debug(__FUNCTION__, "State:" . ($state ? "ON" : "OFF") . ", Dimmer:{$intensity}%,Timer: {$new_timer},ActionCode: '{$actioncode}'"); //state if ($swid) { SetValueBoolean($swid, $state); } //dimmer if ($dvid) { SetValueInteger($dvid, $intensity); } //timer if ($tvid) { $this->SetTimerInterval('DeviceTimer', $new_timer * 1000); SetValueInteger($tvid, $new_timer); } //action if ($avid && $acode != $actioncode) { SetValueString($avid, $actioncode); } //log $actiontext = FHZ_helper::$fs20_codes[strToHex($action)]; if ($ext > 0) { $actiontext .= ', Timer:' . $timer; } $text = sprintf('%s (%s)', $actiontext, strToHex($code)); if ($vid) { SetValueString($vid, $text); } $this->debug(__FUNCTION__, "Action:" . $text); break; default: $this->debug(__FUNCTION__, "{$cap} not handled"); } $this->debug(__FUNCTION__, "{$cap}:({$vid})" . $s); } }
/** * Parse FS20 CUL Hex record * * @code * # F1F1E013A4F * # FHHHHAACCTTSS * # 0123456789012 * @endcode * -HHHH Homecode * -AA Address * -CC FS20code * -TT Timer code * -SS Signal * * @param $line */ private function parse_FS20($line) { $data = array(); $caps = "Switch:1;Timer;FS20;TimerActionCode;"; //enable action for switch and dimmer $hcode = substr($line, 1, 4); $addr = substr($line, 5, 2); $code = substr($line, 7, 2); $acode = hexdec($code); #fix if ($acode > 0x3f) { $acode = $acode & 0x3f; $code = strtoupper(sprintf("%02x", $acode)); $this->debug(__FUNCTION__, "fix Action Code {$code}, Line: {$line}"); } $hc = FHZ_helper::hex2four($hcode . $addr); $action = isset(FHZ_helper::$fs20_codes[$code]) ? FHZ_helper::$fs20_codes[$code] : ''; if (!$action) { $this->incError(); IPS_LogMessage(__CLASS__, __FUNCTION__ . ":: unknown Action Code {$code}, Line: {$line}"); return; } if (isset(FHZ_helper::$FS20_DimCodes[$code])) { $caps .= "Dimmer:1;"; } //timer if ($acode > 31) { $timer = substr($line, 9, 2); $tcode = hexdec($timer); $action .= ' Timer:' . FHZ_helper::fs20_times($tcode); } else { $tcode = 0; } $fs20data = chr($acode) . chr($tcode); //signal $rssi = 0; if (strlen($line) > 11) { $rssi = $this->GetSignal(substr($line, 11, 2)); $data['Signal'] = $rssi; $caps .= 'Signal;'; } else { //signal if (strlen($line) > 9 && $acode < 0x20) { $rssi = $this->GetSignal(substr($line, 9, 2)); $data['Signal'] = $rssi; $caps .= 'Signal;'; } } //make record $data['Typ'] = 'FS20'; //Device FS20 $data['Id'] = $hc; $data['Class'] = __CLASS__ . "-FS20"; $data['FS20'] = utf8_encode($fs20data); //send $text = sprintf('Device:%s(%s), Action:%s (%s), Signal %d', $hc, $hcode . $addr, $action, strToHex($fs20data), $rssi); $this->debug(__FUNCTION__, $text); $this->SendSwitchData($data, $caps); }