Open andryyy opened 3 years ago
Or... no.
After talking to them:
Only 2 bytes of the 4 bytes are used (sigh), furthermore the bytes are flipped.
So: 0C 00 00 00
is 0C 00
is (flipped) 00 0C
is 0000 0000 0000 1100
.
I forgot to mention, that this should equal 1 instead of 0 (for whatever reason it is 0001 0001): https://github.com/studierendenwerk-ulm/payload-decoder-zenner-easy-protect-radio-lora/blob/2ceed382f6d3eb2d81a538cd734c03e98d246da6/decoder.js#L53
Hey, Don't know if this is still active, but I found another decode that has implemented the SP1 payloads. It lacks the 9.2 pyload but maybe you can merge them together: MarkStanley/zenner-lorawan-smoke-detector-payload-decoder Best regards Jonas
Guten Morgen, leider funktionieren beide Decoder bei mir nicht. Ich bekomme keine Decodierung. Ausserdem zeigt es mir im Decoder fehler an: use !== to compare with ´null´
Hi, please check my parser lora.miller-alex.de Use SD device for EasyProtect. Best regards, Alex Miller
Heey Ich habe schon Stunden damit verbracht einen Decoder für Zenner EDC zu erstellen. Leider will er einfach nicht. Hat jemand eine Idee? Das Gateway ist ein UG65 Milesight
`
if (fPort === 1) { // Status bytes decoding var statusByte = bytes[0]; decoded.removal_detection = (statusByte & 0x01) ? 1 : 0; decoded.battery_low = (statusByte & 0x02) ? 1 : 0; decoded.battery_end_of_life = (statusByte & 0x04) ? 1 : 0; decoded.hw_error = (statusByte & 0x08) ? 1 : 0; decoded.coil_manipulation = (statusByte & 0x10) ? 1 : 0;
// Meter values decoding
for (var i = 1; i < bytes.length; i += 4) {
// Assuming meter values are 32-bit unsigned integers
var meterValue = (bytes[i] << 24) | (bytes[i+1] << 16) | (bytes[i+2] << 8) | bytes[i+3];
decoded.meter_values.push(meterValue);
}
}
return decoded; }
`
greeze
I assembled a full decoder, maybe this helps:
function Decoder(bytes, port) {
if(bytes === null || bytes === 0){
obj.status_dedcoded = false;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
} else {
var TYPE_SP1 = 0x1;
var TYPE_SP9 = 0x9;
var SUBTYPE_SP9_1 = 0x01;
var SUBTYPE_SP9_2 = 0x02;
var TYPE_AP1 = 0xA;
var SP_REMOVAL = 0x8000;
var SP_TEST = 0x0001;
var SP_SMOKE = 0x0002;
var SP_OBSTRUCTION = 0x0004;
var SP_MONITORING = 0x0008;
var SP_LED_FAIL = 0x0010;
var SP_BATTERY_EOL = 0x0200;
var SP_CHAMBER_PRE_POLLUTION = 0x0800;
var SP_HORN_FAIL = 0x4000
var SP_CHAMBER_POLLUTION = 0x1000;
var SP_TEST_BUTTON_FAIL = 0x2000;
var SP9_REMOVAL = 0x01;
var SP9_BATTERY_EOL = 0x04;
var SP9_HORN_FAIL = 0x08;
var SP9_OBSTRUCTION = 0x10;
var SP9_MONITORING = 0x20;
var A_REMOVAL = 0x02;
var A_BATTERY_END_OF_LIFE = 0x0C;
var A_HORN_DRIVE_LEVEL_FAILURE = 0x16;
var A_TEST_ALARM = 0x18;
var A_SMOKE_ALARM = 0x19;
var A_OBSTRUCTION_DETECTION = 0x1A;
var A_OBJECT_IN_THE_SURROUNDING_AREA = 0x1C;
var obj = {};
obj.removal = 0;
obj.test_alarm = 0;
obj.smoke_alarm = 0;
obj.obstruction = 0;
obj.monitoring_area = 0;
obj.led_fail = 0;
obj.test_button_fail = 0;
obj.chamber_pollution = 0;
obj.chamber_pollution_pre_warning = 0;
obj.horn_fail = 0;
obj.battery_eol = 0;
obj.object_in_area = 0;
obj.port = port;
switch (bytes[0] >> 4) {
case TYPE_SP1:
obj.packet_type = 1;
obj.packet_subtype = 0;
obj.packet_type_info = "synchronous";
obj.status_dedcoded = true;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
if (bytes[1] & SP_REMOVAL) {
obj.removal = 1;
}
if (bytes[1] & SP_TEST) {
obj.test_alarm = 1;
}
if (bytes[1] & SP_SMOKE) {
obj.smoke_alarm = 1;
}
if (bytes[1] & SP_OBSTRUCTION) {
obj.obstruction = 1;
}
if (bytes[1] & SP_MONITORING) {
obj.monitoring_area = 1;
}
if (bytes[1] & SP_LED_FAIL) {
obj.led_fail = 1;
}
if (bytes[1] & SP_TEST_BUTTON_FAIL){
obj.test_button_fail = 1;
}
if (bytes[1] & SP_CHAMBER_POLLUTION){
obj.chamber_pollution = 1;
}
if (bytes[1] & SP_CHAMBER_PRE_POLLUTION){
obj.chamber_pollution_pre_warning = 1;
}
if (bytes[1] & SP_HORN_FAIL){
obj.horn_fail = 1;
}
if (bytes[1] & SP_BATTERY_EOL){
obj.battery_eol = 1;
}
break;
case TYPE_AP1:
obj.packet_type = 1;
obj.packet_subtype = 0;
obj.packet_type_info = "asynchronous";
obj.date = (decodeDate(bytes [3] << 8 | bytes[4]));
obj.status_interpretation = null;
obj.status_dedcoded = true;
obj.status_info = null;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
switch (bytes[1]) {
case A_REMOVAL:
obj.removal = 1;
break;
case A_BATTERY_END_OF_LIFE:
obj.battery_eol = 1;
break;
case A_HORN_DRIVE_LEVEL_FAILURE:
obj.horn_fail = 1;
break;
case A_TEST_ALARM:
obj.test_alarm = 1;
break;
case A_SMOKE_ALARM:
obj.smoke_alarm = 1;
break;
case A_OBSTRUCTION_DETECTION:
obj.obstruction = 1;
break;
case A_OBJECT_IN_THE_SURROUNDING_AREA:
obj.object_in_area = 1;
break;
default:
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
obj.status_dedcoded = false;
break;
}
break;
case TYPE_SP9:
obj.packet_type = 9;
obj.packet_type_info = "synchronous";
switch (bytes[0] & 0x0F) {
case SUBTYPE_SP9_1:
obj.packet_subtype = 1
obj.date = (decodeSP9Date(bytes[4] << 8 | bytes[3]));
if (bytes[5] & SP9_REMOVAL) {
obj.removal = 1;
}
if (bytes[5] & SP9_BATTERY_EOL) {
obj.battery_eol = 1;
}
if (bytes[5] & SP9_HORN_FAIL) {
obj.horn_fail = 1;
}
if (bytes[5] & SP9_OBSTRUCTION) {
obj.obstruction = 1;
}
if (bytes[5] & SP9_MONITORING) {
obj.monitoring_area = 1;
}
obj.status_dedcoded = true;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
break;
case SUBTYPE_SP9_2:
obj.packet_subtype = 2;
obj.firmware_version = (
((bytes[1] << 24) + (bytes[2] << 16) + (bytes[3] << 8) + (bytes[4]))
.toString(16)).toUpperCase();
obj.LoRa_WAN_version = (bytes[5]).toString(16) + "." + (bytes[6])
.toString(16) + "." + (bytes[7]).toString(16);
obj.LoRa_command_version = (bytes[9]).toString(16) + "." + (bytes[8]).toString(16),
"device type: " + (bytes[10]).toString(16);
obj.device_type = (bytes[10]).toString(16);
obj.meter_ID = (((bytes[11] << 24) + (bytes[12] << 16) + (bytes[13] << 8) + (bytes[14]))
.toString(16)).toUpperCase();
obj.status_dedcoded = true;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
break;
default:
obj.status_dedcoded = false;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
break;
}
break;
default:
obj.status_dedcoded = false;
obj.status_info = "payload_raw: " + payloadRawHexToString(bytes);
break;
}
}
return obj;
}
function decodeDate(bytes) {
var day = (bytes & 0x1F00) >> 8;
var month = (bytes & 0x000F);
var year = ((bytes & 0xE000) >> 10) | ((bytes & 0x00F0) >> 4);
return "20" + year.toString() + "-" + month.toString() + "-" + day.toString();
}
function decodeSP9Date(bytes) {
var day = (bytes & 0x001F);
var month = (bytes & 0x0F00) >> 8;
var year = ((bytes & 0xF000) >> 9) | ((bytes & 0x00E0) >> 5);
return "20" + year.toString() + "-" + month.toString() + "-" + day.toString();
}
function payloadRawHexToString(byteArray) {
var str;
if(byteArray === null){
return "00";
}else {
str = byteArray.map(function (byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
var strArray = str.match(/.{2}/g);
str = strArray.map(function (value, index, array) {
return array[index];
});
var x = str.join();
return x.replace(/([,])/g, " ").toLocaleUpperCase();
}
}
function decodeUplink(input) {
payload=Decoder(input.bytes, input.fPort)
return {
data: payload,
warnings: [],
errors: []
};
}
Funny place for this information, but in case someone’s interested: I have about 5 or 6 of them lying around that I don’t need anymore.
Hi,
I think this should be an A. :) But that would mean the types need to be strings: https://github.com/studierendenwerk-ulm/payload-decoder-zenner-easy-protect-radio-lora/blob/2ceed382f6d3eb2d81a538cd734c03e98d246da6/decoder.js#L97
I am still struggling with the SP1 packages, but I think I understood it now...
Payload seems to be "11 XX XX XX XX" where 1 is SP1 and 1 is oddly enough a subtype 1 (while there is no subtype defined).
The examples make sense then...
The second example
0C 00 00 00
was always a bit tricky for me. It will equal to0011 0000 0000 0000
in binary. Reverse it to0000 0000 0000 1100
and the table above will match.André