=8) {$RecordType=ord(substr($PostData,0,1));} $s=0; //Przesłane dane składają się z jednego lub wielu rekordów. //Na początku każdego rekordu znajduje się bajt określający jego typ i bajt zawierający długość rekordu. while($PostLen-$s>=25) { //typ rekordu: // 0-rekord wysyłany przez iNode Care GSM wg. harmonogramu // 1-rekord wysyłany iNode Care GSM gdy wystąpił alarm // 2-rekord wysyłany iNode Care GSM gdy alarm zaniknął // 128 -rekord wysyłany przez iNode LORA GSM wg. harmonogramu $RecordType=ord(substr($PostData,$s,1)); $DataLen=ord(substr($PostData,$s+1,1)); if ($RecordType==128) //Ramka dla wersji LORA { //Pobranie unikalnego adresu MAC czujnika z jakiego odebrano rekord. //Do pliku o takiej nazwie zostaną zapisane dane. $DevMac=""; for($i = 0; $i < 6; $i++) {$DevMac.=sprintf("%02X", ord(substr($PostData,$s+7-$i,1)));} //Pobranie przyjaznej nazwy czujnika (przesyłana jest opcjonalnie) $DevName=""; for($i = 0; $i < 16; $i++) { if (ord(substr($PostData,$s+8+$i,1))==0) {break;} $DevName.=substr($PostData,$s+8+$i,1); } $DevType=ord(substr($PostData,$s+35,1)); $DevSubType=ord(substr($PostData,$s+34,1))>>4; $DevNotify=ord(substr($PostData,$s+34,1)) & 0x0f; //Obliczeie rzeczywistego czasu odebrania pakietu $PacketTime=$DeviceTime - (ord(substr($PostData,$s+24,1)) | ord(substr($PostData,$s+25,1))<<8 | ord(substr($PostData,$s+26,1))<<16 | ord(substr($PostData,$s+27,1))<<24); //Licznik czasu (sekund) w urządzeniu jest 4-bajtowy. Może więć się "przekęcić". if ($PacketTime<0) {$PacketTime=$PacketTime+0x100000000;} if ($DevType==0x82) {$Batt=(ord(substr($PostData,$s+44,1)))>>4;} else if($DevType==0x8f) {$Batt=(ord(substr($PostData,$s+36,1)))>>4;} else {$Batt=(ord(substr($PostData,$s+37,1)))>>4;} if ($DevType==0x82) {$p=$s+32;} // od tej pozycji zaczyna się ramka z pomiarami else {$p=$s+34;} // od tej pozycji zaczyna się ramka z pomiarami //dane telemetryczne dotyczące połączenia przez Lora $Rssi=ord(substr($PostData,$s+$DataLen+1,1)); $Sn=ord(substr($PostData,$s+5,1)); if ($Sn & 0x80) {$Sn=$Sn-256;} if (SSn==127) {$Radio="GFSK";} else {$Radio="LORA";} } else //Ramka dla wersji Bluetooth { //typ czujnka, który wysłał dane $DevType=ord(substr($PostData,$s+3,1)); $DevSubType=ord(substr($PostData,$s+2,1))>>4; $DevNotify=ord(substr($PostData,$s+2,1)) & 0x0f; //Pobranie unikalnego adresu MAC czujnika z jakiego odebrano rekord. //Do pliku o takiej nazwie zostaną zapisane dane. $DevMac=""; for($i = 0; $i < 6; $i++) {$DevMac.=sprintf("%02X", ord(substr($PostData,$s+9-$i,1)));} //Pobranie przyjaznej nazwy czujnika (przesyłana jest opcjonalnie) $DevName=""; for($i = 0; $i < 16; $i++) { if (ord(substr($PostData,$s+10+$i,1))==0) {break;} $DevName.=substr($PostData,$s+10+$i,1); } $p=$s+22; // od tej pozycji zaczyna się ramka z pomiarami //Obliczeie rzeczywistego czasu odebrania pakietu if ($DeviceTime!=-1) { $PacketTime=($DeviceTime & 0xffffff) - (ord(substr($PostData,$p+15,1)) | ord(substr($PostData,$p+16,1))<<8 | ord(substr($PostData,$p+17,1))<<16); //Licznik czasu (sekund) w urządzeniu jest 3-bajtowy. Co pół roku może się "przekęcić". if ($PacketTime<0) {$PacketTime=$PacketTime+0x1000000;} } else {$PacketTime=0;} if ($RecordType==0) {$Batt=ord(substr($PostData,$p+12,1));} else {$Batt=ord(substr($PostData,$p+13,1))>>4;} //dla pakietów alarmowych (wymagany firmware z 04.05.2018 lub nowszy) //dane telemetryczne dotyczące połączenia przez Bluetooth $Rssi=ord(substr($PostData,$p+14,1)); $Sn=""; $Radio="BT"; } $PacketTime=date("Y-m-d H:i:s", $PostTime-$PacketTime); //zapamiętanie danych telemerycznych if ($Rssi & 0x80) {$Rssi=$Rssi-256;} $out=""; $SensorType="?"; switch ($DevType) { case 0x01: //Beacon (nie tylko iNode) $SensorType="Beacon"; $Batt=""; $DevAlarm=0; $out=$PacketTime.",,,,,".$Rssi.",".$Sender."\r\n"; break; case 0x81: //Beacon Care $SensorType="Beacon Care"; $DevTemp=GetUint16($PostData,$p+8); if ($DevNotify & 0x08) {$DevHall=1;} else {$DevHall=0;} if ($DevTemp & 0x1000) {$DevTemp=$DevTemp-0x2000;} else {$DevTemp=$DevTemp & 0x1fff;} $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevHall.",,,".$Rssi.",".$Sender."\r\n"; break; case 0x82: //iNode Energy $SensorType="Energy Meter"; $DevEnAvg=GetUint16($PostData,$p+4); $DevEnSum=GetUint32($PostData,$p+6); $DevConst=GetUint16($PostData,$p+10); $DevConst=$DevConst & 0x3fff; $DevAlarm=0; $Lum=$Batt & 0x0f; $Batt=$Batt>>4; if ($DevConst!=0) {$out=$PacketTime.",,".sprintf("%01.2f",$DevEnSum/$DevConst).",".sprintf("%01.2f",60*$DevEnAvg/$DevConst).",".sprintf("%d",DevConst>>14).",".$Lum.",\r\n";} break; case 0x8F: //LORA-UART //$FrameType=ord(substr($PostData,$p+2,1)) & 0x0f; if ($DevSubTypee==0 && GetRevUint16($PostData,$p+5)==0x424D) { $SensorType="Air"; $DevAlarm=0; $DevTemp=GetUint16($PostData,$p+3) & 0x1fff; if ($DevTemp & 0x1000) {$DevTemp=$DevTemp-0x2000;} else {$DevTemp=$DevTemp & 0x1fff;} $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16); for ($i=0;$i<3;$i++) {$out=$out.",".GetRevUint16($PostData,$p+15+2*$i);} $out=$out."\r\n"; } break; case 0x91: //Care Sensor #1 $SensorType="Care #1"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevAcc=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); $DevTemp=$DevTemp & 0x1fff; if ($DevTemp & 0x1000) {$DevTemp=$DevTemp-0x2000;} else {$DevTemp=$DevTemp & 0x1fff;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",,".sprintf("0x%04X",$DevAcc).",,,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",,".sprintf("0x%04X",$DevAcc).",,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",,".sprintf("0x%04X",$DevAcc).",,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x92: //Care Sensor #2 $SensorType="Care #2"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevAcc=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); $DevTemp=($DevTemp & 0xfff)*0.0625; if (ord(substr($PostData,$p+9,1)) & 0x10) {$DevTemp=$DevTemp-256;} if ($DevTemp>70) {$DevTemp=70;} if ($DevTemp<-30) {$DevTemp=-30;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",,".sprintf("0x%04X",$DevAcc).",,,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",,".sprintf("0x%04X",$DevAcc).",,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",,".sprintf("0x%04X",$DevAcc).",,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x93: //Care Sensor #3 $SensorType="Care #3"; $DevAlarm=GetUint16($PostData,$p+4) & 0xfff; $DevAcc=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); $DevHum=GetUint16($PostData,$p+10); //ord(substr($PostData,$p+10,1)) | ord(substr($PostData,$p+11,1))<<8; $$DevTemp=($DevTemp*175.72)/16384-46.85; if ($DevTemp>70) {$DevTemp=70;} if ($DevTemp<-30) {$DevTemp=-30;} $DevHum=($DevHum*125)/16384-6; if ($DevHum>100) {$DevHum=100;} if ($DevHum<0) {$DevHum=0;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("0x%04X",$DevAcc).",,,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("0x%04X",$DevAcc).",,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("0x%04X",$DevAcc).",,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x94: //Care Sensor #4 $SensorType="Care #4"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevAcc=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); if ($DevNotify & 0x08) {$DevHall=1;} else {$DevHall=0;} $DevTemp=$DevTemp & 0x1fff; if ($DevTemp & 0x1000) {$DevTemp=$DevTemp-0x2000;} else {$DevTemp=$DevTemp & 0x1fff;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",".$DevAlarm.",,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x95: //Care Sensor #5 $SensorType="Care #5"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevAcc=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); $DevCnt=GetUint16($PostData,$p+10); if ($DevTemp & 0x8000) {$DevTemp=$DevTemp-65536;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%d",$DevTemp).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%d",$DevTemp).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%d",$DevTemp).",".$DevHall.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x9B: //Care Sensor HT oraz Care Sensor T układem Si715x $SensorType="Care T"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevTemp=GetUint16($PostData,$p+8); $DevTemp=($DevTemp*175.72)/16384-46.85; if ($DevTemp>70) {$DevTemp=70;} if ($DevTemp<-40) {$DevTemp=-40;} $DevHum=""; //Ukłądy Si715x maja higrometr ale nie jest on aktywny if ($DevSubType<0x0a) //Care Sensor HT { $SensorType="Care HT"; $DevHum=GetUint16($PostData,$p+10); $DevHum=($DevHum*125)/16384-6; if ($DevHum>100) {$DevHum=100;} if ($DevHum<0) {$DevHum=0;} $DevHum=sprintf("%01.2f",$DevHum); } switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".$DevHum.",,,,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".$DevHum.",,,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".$DevHum.",,,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x9D: //Care Sensor PHT $SensorType="Care PHT"; $DevAlarm=GetUint16($PostData,$p+4) & 0x0fff; $DevPress=GetUint16($PostData,$p+6); $DevTemp=GetUint16($PostData,$p+8); $DevHum=GetUint16($PostData,$p+10); $DevTemp=($DevTemp*175.72)/16384-46.85; if ($DevTemp>70) {$DevTemp=70;} if ($DevTemp<-30) {$DevTemp=-30;} $DevHum=($DevHum*125)/16384-6; if ($DevHum>100) {$DevHum=100;} if ($DevHum<0) {$DevHum=0;} $DevPress=$DevPress/16; if ($DevPress>1270) {$DevPress=1270;} if ($DevPress<260) {$DevPress=260;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("%01.1f",$DevPress).",,,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("%01.1f",$DevPress).",,".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp).",".sprintf("%01.2f",$DevHum).",".sprintf("%01.1f",$DevPress).",,,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; case 0x9F: //Care L $SensorType="Care L"; $DevAlarm=GetUint16($PostData,$p+12) & 0x0fff; $DevLight=GetUint16($PostData,$p+6); $DevLight=($DevLight & 0x0fff)<<($DevLight>>12); $DevLight=1.2*$DevLight/100000; $DevTemp=GetUint16($PostData,$p+8); $DevCnt=GetUint16($PostData,$p+10); $DevTemp=$DevTemp & 0x1fff; if ($DevTemp & 0x1000) {$DevTemp=$DevTemp-0x2000;} else {$DevTemp=$DevTemp & 0x1fff;} switch ($RecordType) { case 0: case 128: $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevLight.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",,\r\n"; break; case 1: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevLight.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",".sprintf("%d",AlarmNumber($MsgAlarm)).",\r\n"; break; case 2: $MsgAlarm=GetUint16($PostData,$p+12); //przyczyna wysłania pakietu alarmowego $out=$PacketTime.",".sprintf("%01.2f",$DevTemp/16).",".$DevLight.",".sprintf("0x%04X",$DevAcc).",".sprintf("%d",$DevCnt).",,".sprintf("%d",AlarmNumber($MsgAlarm))."\r\n"; break; } break; } //Obliczenie wskaźnika do początku kolejnego rekordu. $s=$s+$DataLen+2; if ($out!="") { //Zapis danych do pliku o nazwie będącej adresem MAC czujnika. $File = fopen($DevMac.".csv","a"); fwrite($File, $out); fclose($File); if ($Batt!="") { if ($DevNotify & 0x04) {$Batt=($Batt-2)*0.03+3.3;} //gdy napięcie jest większe niż 3V else {$Batt=($Batt-2)*0.12+1.8;} //gdy napięcie jest mniejsze niż 3V } //Dodanie do tablicy $Devices informacji telemetrycznych dotyczących danego urządzenia //W specyficznych sytuacjach może się zdarzyć, że będzie kilka rekordów dotyczących tego samego czujnika. //Z tego powodu tablica przed dodaniem danych jest przeglądana. foreach($Devices as $record) { if ($DevMac==$record[0]) {continue 2; } } array_push($Devices,array($DevMac,$SensorType,$DevName,$Radio,$PacketTime,$Sender,filesize($DevMac.".csv"),$DevAlarm,$Batt,$Rssi,$Sn)); } } //Zapis danych do pliku o nazwie pobrane z pola HTTP_USER_AGENT /* $out=$PacketTime; foreach($Devices as $record) {$out=$out.",".$record[0];} $out=$out."\r\n"; $File = fopen($Sender.".csv","a"); fwrite($File, $out); fclose($File); */ //Dodanie do tablicy $Devices informacji archiwalnych z pliku "devices.csv". if (file_exists($DevFile)) { $File = fopen($DevFile,"r"); while (($data = fgetcsv($File, 1000, ",")) !== FALSE) { foreach($Devices as $record) { if ($data[0]==$record[0]) {continue 2; } } array_push($Devices,$data); } fclose($File); } //Zamiana pliku "devices.csv" na nowy. $File = fopen($DevFile,"w"); foreach($Devices as $record) //{fputcsv($File, $record, ',', '"');} {{fwrite($File, implode(',', $record). "\r\n");}} fclose($File); //W celach testowych można zapisać odebrane dane w formie binarnej do pliku. /* $File = fopen("post.bin","wb"); fwrite($File,$PostData); fclose($File); */ //Serwer potwierdza odebranie danych odsyłająć "OK" //Zamiast OK serwer może wysłać do iNode GSM jakiś rozkaz np. odczytania danych z wewnętrznej pamięci czujnika echo "OK"; //echo "CMD=ReadEeprom&ADDR=00126FCF6CC1&SYNC=0&PSWD=36383935000000000000000000000000&CLEAR=NO"; //echo "CMD=ReadEeprom&ADDR=00126F913810&SYNC=0&PSWD=31323334000000000000000000000000&CLEAR=YES&LEN=123"; //echo "CMD=GetFirmware&URL=159.205.245.44&PORT=8124&APN=internet"; //echo "CMD=SetSettings&HTTP_TEST=20"; //echo "CMD=HciReset"; function AlarmNumber($alarms) { $mask=0x0001; for ($i = 1; $i <= 12; $i++) { if ($alarms & $mask) {return $i;} $mask=$mask<<1; } return 0; } function GetUint16($data, $index) {return ord(substr($data,$index,1)) | ord(substr($data,$index+1,1))<<8;} function GetUint32($data, $index) {return ord(substr($data,$index,1)) | ord(substr($data,$index+1,1))<<8 | ord(substr($data,$index+2,1))<<16 | ord(substr($data,$index+3,1))<<24;} function GetRevUint16($data, $index) { return ord(substr($data,$index,1))<<8 | ord(substr($data,$index+1,1)); } ?>