-
Notifications
You must be signed in to change notification settings - Fork 388
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding MClimate CO2 Display and Fan Coil Thermostat (#698)
* MClimate - Vicki,T-valve,Flood,Ht,AQI * update aqi sensors * update device names * remove scripts * Key security fix * fix yaml, * fix reseller urls * remove scripts * remove reseller vicki * remove ressellerUrls * profile * fix sensors * img * change flood img * aqi, ht img * prettier * prettier * prettier * uplink decoders, update aqi info * prettier again... * Pretttier again... * new Vicki uplinkDecoder, fix versions * return shorter decoder * update uplink decoders * New mclimate device CO2 sensor * new Vicki version and decoder * new version Vicki, new decoder ht/co2, remove AQI * add MClimate wireless thermostat * mclimate wireless thermostat fix image name * MClimate wireless thermostat prettier * vicki 4.2 * fix vicki codec * fix Mclimate wireless thermostat decoder * MClimate CO2 Display + Fan Coil Thermostat * Prettier * prettied --------- Co-authored-by: Yordan Zaychev <[email protected]> Co-authored-by: Johan Stokking <[email protected]> Co-authored-by: Jaime Trinidad <[email protected]>
- Loading branch information
1 parent
c0550c5
commit 6e7a481
Showing
12 changed files
with
928 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
uplinkDecoder: | ||
fileName: co2-display.js | ||
examples: | ||
- description: Periodic uplink | ||
input: | ||
fPort: 2 | ||
bytes: [0x01, 0x02, 0x67, 0x82, 0x0B, 0x7C, 0x93, 0x20, 0x00, 0x37, 0x00] | ||
output: | ||
data: | ||
sensorTemperature: 21.5 | ||
relativeHumidity: 50.78 | ||
batteryVoltage: 2.94 | ||
ppm: 1171 | ||
powerSourceStatus: 0 | ||
lux: 55 | ||
pir: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
vendorProfileID: 824 | ||
supportsClassB: false | ||
supportsClassC: false | ||
macVersion: 1.0.3 | ||
regionalParametersVersion: RP001-1.0.3-RevA | ||
supportsJoin: true | ||
maxEIRP: 16 | ||
supports32bitFCnt: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
function decodeUplink(input) { | ||
try{ | ||
var bytes = input.bytes; | ||
var data = {}; | ||
const toBool = value => value == '1'; | ||
var calculateTemperature = function (rawData){return (rawData - 400) / 10}; | ||
var calculateHumidity = function(rawData){return (rawData * 100) / 256}; | ||
var decbin = function (number) { | ||
if (number < 0) { | ||
number = 0xFFFFFFFF + number + 1 | ||
} | ||
number = number.toString(2); | ||
return "00000000".substr(number.length) + number; | ||
} | ||
function handleKeepalive(bytes, data){ | ||
var tempHex = '0' + bytes[1].toString(16) + bytes[2].toString(16); | ||
var tempDec = parseInt(tempHex, 16); | ||
var temperatureValue = calculateTemperature(tempDec); | ||
var humidityValue = calculateHumidity(bytes[3]); | ||
var batteryHex = '0' + bytes[4].toString(16) + bytes[5].toString(16); | ||
var batteryVoltageCalculated = parseInt(batteryHex, 16)/1000; | ||
var temperature = temperatureValue; | ||
var humidity = humidityValue; | ||
var batteryVoltage = batteryVoltageCalculated; | ||
var ppmBin = decbin(bytes[6]); | ||
var ppmBin2 = decbin(bytes[7]); | ||
ppmBin = `${ppmBin2.slice(0,5)}${ppmBin}` | ||
var ppm = parseInt(ppmBin, 2); | ||
var powerSourceStatus = ppmBin2.slice(5,8); | ||
var lux = parseInt('0' + bytes[8].toString(16) + bytes[9].toString(16), 16); | ||
var pir = toBool(bytes[10]); | ||
data.sensorTemperature = Number(temperature.toFixed(2)); | ||
data.relativeHumidity = Number(humidity.toFixed(2)); | ||
data.batteryVoltage = Number(batteryVoltage.toFixed(3)); | ||
data.ppm = ppm; | ||
data.powerSourceStatus = parseInt(powerSourceStatus,2); | ||
data.lux = lux; | ||
data.pir = pir; | ||
return data; | ||
} | ||
|
||
function handleResponse(bytes, data){ | ||
var commands = bytes.map(function(byte){ | ||
return ("0" + byte.toString(16)).substr(-2); | ||
}); | ||
commands = commands.slice(0,-11); | ||
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 '14': | ||
{ | ||
command_len = 1; | ||
data.childLock = toBool(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 deviceKeepAlive = 5; | ||
var wdpC = commands[i + 1] == '00' ? false : commands[i + 1] * deviceKeepAlive + 7; | ||
var wdpUc = commands[i + 2] == '00' ? false : parseInt(commands[i + 2], 16); | ||
data.watchDogParams= { wdpC: wdpC, wdpUc: wdpUc } ; | ||
} | ||
break; | ||
case '1f': | ||
{ | ||
command_len = 4; | ||
var good_medium = parseInt(commands[i + 1] +'' + commands[i + 2], 16); | ||
var medium_bad = parseInt(commands[i + 3] +'' + commands[i + 4], 16); | ||
|
||
data.boundaryLevels = { good_medium: Number(good_medium), medium_bad: Number(medium_bad) } ; | ||
} | ||
break; | ||
case '21': | ||
{ | ||
command_len = 2; | ||
data.autoZeroValue = parseInt(commands[i + 1] +'' + commands[i + 2], 16); | ||
} | ||
break; | ||
case '25': | ||
{ | ||
|
||
command_len = 3; | ||
var good_zone = parseInt(commands[i + 1], 16); | ||
var medium_zone = parseInt(commands[i + 2], 16); | ||
var bad_zone = parseInt(commands[i + 3], 16); | ||
|
||
data.measurementPeriod = { good_zone: Number(good_zone), medium_zone: Number(medium_zone), bad_zone: Number(bad_zone) } ; | ||
} | ||
break; | ||
case '2b': | ||
{ | ||
command_len = 1; | ||
data.autoZeroPeriod = parseInt(commands[i + 1], 16); | ||
} | ||
break; | ||
case '34': | ||
{ | ||
command_len = 1; | ||
data.displayRefreshPeriod = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '3d': | ||
{ | ||
command_len = 1; | ||
data.pirSensorStatus = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '3f': | ||
{ | ||
command_len = 1; | ||
data.pirSensorSensitivity = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '41': | ||
{ | ||
command_len = 1; | ||
data.currentTemperatureVisibility = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '43': | ||
{ | ||
command_len = 1; | ||
data.humidityVisibility = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '45': | ||
{ | ||
command_len = 1; | ||
data.lightIntensityVisibility = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '47': | ||
{ | ||
command_len = 1; | ||
data.pirInitPeriod = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '49': | ||
{ | ||
command_len = 1; | ||
data.pirMeasurementPeriod = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '4b': | ||
{ | ||
command_len = 1; | ||
data.pirCheckPeriod = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '4d': | ||
{ | ||
command_len = 1; | ||
data.pirBlindPeriod = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '80': | ||
{ | ||
command_len = 1; | ||
data.measurementBlindTime = parseInt(commands[i + 1], 16) ; | ||
} | ||
break; | ||
case '83': | ||
{ | ||
command_len = 1; | ||
var bin = decbin(parseInt(commands[i + 1], 16)); | ||
var chart = Number(bin[5]); | ||
var digital_value = Number(bin[6]); | ||
var emoji = Number(bin[7]); | ||
data.imagesVisibility = { chart, digital_value, emoji } ; | ||
} | ||
break; | ||
case 'a0': | ||
{ | ||
command_len = 4; | ||
var fuota_address = parseInt(`${commands[i + 1]}${commands[i + 2]}${commands[i + 3]}${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_raw }; | ||
} | ||
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(-11); | ||
data = handleKeepalive(bytes, data); | ||
} | ||
return {data: data}; | ||
} catch (e) { | ||
throw new Error('Unhandled data'); | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
name: MClimate CO2 Display | ||
description: MClimate CO2 Display is a stand-alone CO2 sensor powered entirely by solar energy using an organic solar panel. The device features a 2.9" e-ink screen, sensor for movement (PIR), temperature and humidity sensor, LUX sensor and NDIR CO2 sensor. | ||
|
||
# Hardware versions (optional, use when you have revisions) | ||
hardwareVersions: | ||
- version: '2.6' | ||
numeric: 1 | ||
|
||
# Firmware versions (at least one is mandatory) | ||
firmwareVersions: | ||
- # Firmware version | ||
version: '1.1' | ||
numeric: 1 | ||
hardwareVersions: | ||
- '2.6' | ||
|
||
# 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: co2-display-profile | ||
lorawanCertified: false | ||
codec: co2-display-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 | ||
- humidity | ||
- pir | ||
- light | ||
- co2 | ||
# Dimensions in mm (optional) | ||
# Use width, height, length and/or diameter | ||
dimensions: | ||
width: 115 | ||
length: 23 | ||
height: 105 | ||
|
||
# Weight in grams (optional) | ||
weight: 170 | ||
|
||
# Battery information (optional) | ||
battery: | ||
replaceable: true | ||
type: AA | ||
|
||
# Operating conditions (optional) | ||
operatingConditions: | ||
# Temperature (Celsius) | ||
temperature: | ||
min: 0 | ||
max: 50 | ||
# 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 | ||
|
||
# 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-co2-display | ||
dataSheetURL: https://3008755228-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-McDr-jr9h3qA888r1Yp%2Fuploads%2FayhC2LiSECIybZVCubgn%2FMClimate-CO2-Display-Datasheet.pdf?alt=media&token=94ce5f00-de21-4049-9209-0ffde58f4975 | ||
# 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: co2-display.png | ||
|
||
# Regulatory compliances (optional) | ||
compliances: | ||
safety: | ||
- body: IEC | ||
norm: EN | ||
standard: 62479:2010 | ||
radioEquipment: | ||
- body: ETSI | ||
norm: EN | ||
standard: 60950-1 | ||
- body: ETSI | ||
norm: EN | ||
standard: 301-489 | ||
version: 2.1.1 | ||
- body: ETSI | ||
norm: EN | ||
standard: 300-220 | ||
version: 3.1.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
uplinkDecoder: | ||
fileName: fan-coil-thermostat.js | ||
examples: | ||
- description: Periodic uplink | ||
input: | ||
fPort: 2 | ||
bytes: [0x01, 0x02, 0x88, 0x75, 0x01, 0x3B, 0x01, 0x00, 0x06, 0x01, 0x01] | ||
output: | ||
data: | ||
sensorTemperature: 24.8 | ||
relativeHumidity: 45.7 | ||
targetTemperature: 31.5 | ||
operationalMode: 1 | ||
displayedFanSpeed: 0 | ||
actualFanSpeed: 6 | ||
valveStatus: 1 | ||
deviceStatus: 1 |
Oops, something went wrong.