Skip to content

Commit

Permalink
New MClimate devices: 16ASPM, CO2 Display Lite (#830)
Browse files Browse the repository at this point in the history
* New MClimate devices: 16ASPM, CO2 Display Lite

* New MClimate devices: 16ASPM, CO2 Display Lite

---------

Co-authored-by: Yordan <[email protected]>
  • Loading branch information
MClimate and yordan-zaychev authored Oct 10, 2024
1 parent cabac7d commit ea439fa
Show file tree
Hide file tree
Showing 10 changed files with 692 additions and 0 deletions.
15 changes: 15 additions & 0 deletions vendor/mclimate/16aspm-codec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
uplinkDecoder:
fileName: 16aspm.js
examples:
- description: Periodic uplink
input:
fPort: 2
bytes: [0x01, 0x1C, 0x03, 0x4A, 0x24, 0x18, 0x05, 0xD9, 0xE7, 0x19, 0x52, 0x01]
output:
data:
internalTemperature: 28
energy_kWh: 55190.552,
power_W: 1497,
acVoltage_V: 231,
acCurrent_mA: 6482,
relayState: 'ON'
7 changes: 7 additions & 0 deletions vendor/mclimate/16aspm-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
supportsClassB: false
supportsClassC: true
macVersion: 1.0.3
regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 16
supports32bitFCnt: true
205 changes: 205 additions & 0 deletions vendor/mclimate/16aspm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
function decodeUplink(input) {
try {
var bytes = input.bytes;
var data = {};

function handleKeepalive(bytes, data) {
data.internalTemperature = bytes[1];

// Energy data
var energy = (bytes[2] << 24) | (bytes[3] << 16) | (bytes[4] << 8) | bytes[5];
data.energy_kWh = energy / 1000;

// Power data
var power = (bytes[6] << 8) | bytes[7];
data.power_W = power;

// AC voltage
data.acVoltage_V = bytes[8];

// AC current data
var acCurrent = (bytes[9] << 8) | bytes[10];
data.acCurrent_mA = acCurrent;

// Relay state
data.relayState = bytes[11] === 0x01 ? "ON" : "OFF";
return data;
}

function handleResponse(bytes, data){
var commands = bytes.map(function(byte){
return ("0" + byte.toString(16)).substr(-2);
});
commands = commands.slice(0,-12);
var command_len = 0;

commands.map(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 = 1;
data.overheatingThreshold = parseInt(commands[i + 1], 16);
}
break;
case '21':
{
command_len = 2;
data.overvoltageThreshold = (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16) ;
}
break;
case '23':
{
command_len = 1;
data.overcurrentThreshold = parseInt(commands[i + 1], 16) ;
}
break;
case '25':
{
command_len = 2;
data.overpowerThreshold = (parseInt(commands[i + 1], 16) << 8) | 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 '61':
{
command_len = 3;
data.overvoltageEvents = { events: parseInt(commands[i + 1], 16), voltage: (parseInt(commands[i + 2], 16) << 8) | parseInt(commands[i + 3], 16) };
}
break;
case '62':
{
command_len = 3;
data.overcurrentEvents = { events: parseInt(commands[i + 1], 16), current: (parseInt(commands[i + 2], 16) << 8) | parseInt(commands[i + 3], 16) }
}
break;
case '63':
{
command_len = 3;
data.overpowerEvents = { events: parseInt(commands[i + 1], 16), power: (parseInt(commands[i + 2], 16) << 8) | parseInt(commands[i + 3], 16) };
}
break;
case '70':
{
command_len = 2;
data.overheatingRecoveryTime = (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16) ;
}
break;
case '71':
{
command_len = 2;
data.overvoltageRecoveryTime = (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16);
}
break;
case '72':
{
command_len = 1;
data.overcurrentRecoveryTemp = parseInt(commands[i + 1], 16);
}
break;
case '73':
{
command_len = 1;
data.overpowerRecoveryTemp = parseInt(commands[i + 1], 16);
}
break;
case 'b1':
{
command_len = 1;
data.relayState = parseInt(commands[i + 1], 16) === 0x01
}
break;
case 'a0':
{
command_len = 4;
let fuota_address = parseInt(`${commands[i + 1]}${commands[i + 2]}${commands[i + 3]}${commands[i + 4]}`, 16)
let fuota_address_raw = `${commands[i + 1]}${commands[i + 2]}${commands[i + 3]}${commands[i + 4]}`
data.fuota = { fuota_address, fuota_address_raw };
}
break;
default:
break;
}
commands.splice(i,command_len);
});
return data;
}

if (bytes[0] == 1) {
data = handleKeepalive(bytes, data);
} else {
data = handleResponse(bytes, data);
// Handle the remaining keepalive data if required after response
bytes = bytes.slice(-12);
data = handleKeepalive(bytes, data);
}
return { data: data };
} catch (e) {
// console.log(e);
throw new Error('Unhandled data');
}
}
Binary file added vendor/mclimate/16aspm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
136 changes: 136 additions & 0 deletions vendor/mclimate/16aspm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: МClimate 16A Switch & Power Meter (16ASPM)
description: The МClimate 16A Switch & Power Meter LoRaWAN (16ASPM) is a miniature device that features a wet 16A relay and an electricity meter inside. The device has 4 terminals L, N, N, Lout, connecting and disconnecting Lout from Lin. The device operates in LoRaWAN Class C, features FUOTA (Firmware Upgrades Over The Air) and has overheating protection

# Hardware versions (optional, use when you have revisions)
hardwareVersions:
- version: '1.3'
numeric: 1

# Firmware versions (at least one is mandatory)
firmwareVersions:
- # Firmware version
version: '1.2'
numeric: 1
hardwareVersions:
- '1.3'

# LoRaWAN Device Profiles per region
# Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867, RU864-870
profiles:
EU863-870:
# Unique identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters)
id: 16aspm-profile
lorawanCertified: false
codec: 16aspm-codec

# Sensors that this device features (optional)
# Valid values are: accelerometer, altitude, auxiliary, barometer, battery, button, co2, distance, dust, gps, gyroscope,
# humidity, light, link, magnetometer, moisture, ph, pir, proximity, rssi, snr, sound, temperature, tvoc, velocity,
# vibration, water, wind direction and wind speed.
sensors:
- temperature
- electricity-meter
- voltage-meter
- current-meter
# Dimensions in mm (optional)
# Use width, height, length and/or diameter
dimensions:
width: 36
length: 18
height: 32

# Weight in grams (optional)
weight: 24

# Battery information (optional)
battery:
replaceable: false

# Operating conditions (optional)
operatingConditions:
# Temperature (Celsius)
temperature:
min: -10
max: 40
# Relative humidity (fraction of 1)
relativeHumidity:
min: 0.00
max: 0.80

# IP rating (optional)
ipCode: IP30

# Key provisioning (optional)
# Valid values are: custom (user can configure keys), join server and manifest.
keyProvisioning:
- custom
- manifest

# Key security (optional)
# Valid values are: none, read protected and secure element.
keySecurity: read protected

# Product and data sheet URLs (optional)
productURL: https://docs.mclimate.eu/mclimate-lorawan-devices/devices/mclimate-16a-switch-and-power-meter-lorawan-16aspm
dataSheetURL: https://3940008670-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-McDr-jr9h3qA888r1Yp%2Fuploads%2F6ySZvZUpeLGiEza7qAWz%2FMClimate-16ASPM-Datasheet.pdf?alt=media&token=baf39b06-3946-4f7e-acc3-29faadc0f0e0
# resellerURLs:
# - name: 'Connected Things'
# region:
# - United Kingdom
# url: https://connectedthings.store/
# - name: 'Concept13'
# region:
# - United Kingdom
# url: https://www.concept13.co.uk
# - name: 'RG2i'
# region:
# - France
# url: https://connectedthings.store/
# - name: 'Wideco'
# region:
# - Sweden
# url: https://wideco.se
# - name: 'iioote'
# region:
# - Sweden
# url: https://iiooote.com

# Photos
photos:
main: 16aspm.png

# Regulatory compliances (optional)
compliances:
safety:
- body: IEC
norm: EN
standard: 62368-1:2020
- body: IEC
norm: EN
standard: 61010-1:2010
electromagneticCompatibility:
- body: ETSI
norm: EN
standard: 301489-1
version: 'latest'
- body: ETSI
norm: EN
standard: 301489-17
version: 'latest'
- body: CENELEC
norm: EN
standard: 55032:2015
- body: CENELEC
norm: EN
standard: 55035:2017
radioEquipment:
- body: ETSI
norm: EN
standard: 300220-1
- body: ETSI
norm: EN
standard: 300220-2
lowVoltageDirective:
- body: IEC
norm: EN
standard: 2014/35/EU
15 changes: 15 additions & 0 deletions vendor/mclimate/co2-display-lite-codec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
uplinkDecoder:
fileName: co2-display-lite.js
examples:
- description: Periodic uplink
input:
fPort: 2
bytes: [0x01, 0x02, 0x63, 0x87, 0x0A, 0xAC, 0x39, 0x10, 0x01, 0x17]
output:
data:
sensorTemperature: 21.1
relativeHumidity: 52.73
batteryVoltage: 2.73
CO2: 569
powerSourceStatus: 0
lux: 279
7 changes: 7 additions & 0 deletions vendor/mclimate/co2-display-lite-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
supportsClassB: false
supportsClassC: false
macVersion: 1.0.3
regionalParametersVersion: RP001-1.0.3-RevA
supportsJoin: true
maxEIRP: 16
supports32bitFCnt: true
Loading

0 comments on commit ea439fa

Please sign in to comment.