⬆️MClimate 16ADS Uplink decoder
Universal Decoder:
Supports: The Thinks Network, Milesight, DataCake, Chirpstack
// DataCake
function Decoder(bytes, port){
var decoded = decodeUplink({ bytes: bytes, fPort: port }).data;
return decoded;
}
// Milesight
function Decode(port, bytes){
var decoded = decodeUplink({ bytes: bytes, fPort: port }).data;
return decoded;
}
// The Things Industries / Main
function decodeUplink(input) {
try {
var bytes = input.bytes;
var data = {};
function handleKeepalive(bytes, data) {
// Temperature sign and internal temperature
var isNegative = (bytes[1] & 0x80) !== 0; // Check the 7th bit for the sign
var temperature = bytes[1] & 0x7F; // Mask out the 7th bit to get the temperature value
data.internalTemperature = isNegative ? -temperature : temperature;
// Relay state
data.relayState = bytes[2] === 0x01 ? "ON" : "OFF";
return data;
}
function handleResponse(bytes, data) {
var commands = bytes.map(function (byte) {
return ("0" + byte.toString(16)).substr(-2);
});
var command_len = 0;
commands.forEach(function (command, i) {
switch (command) {
case '04': {
command_len = 2;
var hardwareVersion = commands[i + 1];
var softwareVersion = commands[i + 2];
data.deviceVersions = {
hardware: Number(hardwareVersion),
software: Number(softwareVersion),
};
break;
}
case '12': {
command_len = 1;
data.keepAliveTime = parseInt(commands[i + 1], 16);
break;
}
case '19': {
command_len = 1;
var commandResponse = parseInt(commands[i + 1], 16);
var periodInMinutes = (commandResponse * 5) / 60;
data.joinRetryPeriod = periodInMinutes;
break;
}
case '1b': {
command_len = 1;
data.uplinkType = parseInt(commands[i + 1], 16);
break;
}
case '1d': {
command_len = 2;
var wdpC = commands[i + 1] === '00' ? false : parseInt(commands[i + 1], 16);
var wdpUc = commands[i + 2] === '00' ? false : parseInt(commands[i + 2], 16);
data.watchDogParams = { wdpC: wdpC, wdpUc: wdpUc };
break;
}
case '1f': {
command_len = 2;
data.overheatingThresholds = {
trigger: parseInt(commands[i + 1], 16),
recovery: parseInt(commands[i + 2], 16),
};
break;
}
case '5a': {
command_len = 1;
data.afterOverheatingProtectionRecovery = parseInt(commands[i + 1], 16);
break;
}
case '5c': {
command_len = 1;
data.ledIndicationMode = parseInt(commands[i + 1], 16);
break;
}
case '5d': {
command_len = 1;
data.manualChangeRelayState = parseInt(commands[i + 1], 16) === 0x01;
break;
}
case '5f': {
command_len = 1;
data.relayRecoveryState = parseInt(commands[i + 1], 16);
break;
}
case '60': {
command_len = 2;
data.overheatingEvents = {
events: parseInt(commands[i + 1], 16),
temperature: parseInt(commands[i + 2], 16),
};
break;
}
case '70': {
command_len = 2;
data.overheatingRecoveryTime = (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16);
break;
}
case 'b1': {
command_len = 1;
data.relayState = parseInt(commands[i + 1], 16) === 0x01;
break;
}
case 'a0': {
command_len = 4;
var fuota_address = (parseInt(commands[i + 1], 16) << 24) |
(parseInt(commands[i + 2], 16) << 16) |
(parseInt(commands[i + 3], 16) << 8) |
parseInt(commands[i + 4], 16);
var fuota_address_raw = commands[i + 1] + commands[i + 2] +
commands[i + 3] + commands[i + 4];
data.fuota = { fuota_address: fuota_address, fuota_address_raw: fuota_address_raw };
break;
}
case 'a4': {
command_len = 1;
data.region = parseInt(commands[i + 1], 16);
break;
}
default:
break;
}
commands.splice(i, command_len);
});
return data;
};
if (bytes[0] === 1) {
data = handleKeepalive(bytes, data);
} else {
data = handleResponse(bytes, data);
bytes = bytes.slice(-3);
data = handleKeepalive(bytes, data);
}
return { data: data };
} catch (e) {
console.log(e);
throw new Error('Unhandled data');
}
};
Last updated
Was this helpful?