diff --git a/vendor/mclimate/co2-display-codec.yaml b/vendor/mclimate/co2-display-codec.yaml new file mode 100644 index 0000000000..4288d938de --- /dev/null +++ b/vendor/mclimate/co2-display-codec.yaml @@ -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 diff --git a/vendor/mclimate/co2-display-profile.yaml b/vendor/mclimate/co2-display-profile.yaml new file mode 100644 index 0000000000..bfee76c3ad --- /dev/null +++ b/vendor/mclimate/co2-display-profile.yaml @@ -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 diff --git a/vendor/mclimate/co2-display.js b/vendor/mclimate/co2-display.js new file mode 100644 index 0000000000..f9a5fc9561 --- /dev/null +++ b/vendor/mclimate/co2-display.js @@ -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'); + } +} \ No newline at end of file diff --git a/vendor/mclimate/co2-display.png b/vendor/mclimate/co2-display.png new file mode 100644 index 0000000000..f81bc26710 Binary files /dev/null and b/vendor/mclimate/co2-display.png differ diff --git a/vendor/mclimate/co2-display.yaml b/vendor/mclimate/co2-display.yaml new file mode 100644 index 0000000000..88510907a6 --- /dev/null +++ b/vendor/mclimate/co2-display.yaml @@ -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 diff --git a/vendor/mclimate/fan-coil-thermostat-codec.yaml b/vendor/mclimate/fan-coil-thermostat-codec.yaml new file mode 100644 index 0000000000..59279183d3 --- /dev/null +++ b/vendor/mclimate/fan-coil-thermostat-codec.yaml @@ -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 diff --git a/vendor/mclimate/fan-coil-thermostat-profile.yaml b/vendor/mclimate/fan-coil-thermostat-profile.yaml new file mode 100644 index 0000000000..4b4945947c --- /dev/null +++ b/vendor/mclimate/fan-coil-thermostat-profile.yaml @@ -0,0 +1,8 @@ +vendorProfileID: 824 +supportsClassB: false +supportsClassC: true +macVersion: 1.0.3 +regionalParametersVersion: RP001-1.0.3-RevA +supportsJoin: true +maxEIRP: 16 +supports32bitFCnt: true diff --git a/vendor/mclimate/fan-coil-thermostat.js b/vendor/mclimate/fan-coil-thermostat.js new file mode 100644 index 0000000000..da844f80c6 --- /dev/null +++ b/vendor/mclimate/fan-coil-thermostat.js @@ -0,0 +1,331 @@ +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 tempDec = parseInt(`${decbin(bytes[1])}${decbin(bytes[2])}`, 2); + var temperatureValue = calculateTemperature(tempDec); + var humidityValue = calculateHumidity(bytes[3]); + var targetTemperature = parseInt(`${decbin(bytes[4])}${decbin(bytes[5])}`, 2) / 10; + var operationalMode = bytes[6]; + var displayedFanSpeed = bytes[7]; + var actualFanSpeed = bytes[8]; + var valveStatus = bytes[9]; + var deviceStatus = bytes[10]; + + data.sensorTemperature = Number(temperatureValue.toFixed(2)); + data.relativeHumidity = Number(humidityValue.toFixed(2)); + data.targetTemperature = targetTemperature; + data.operationalMode = operationalMode; + data.displayedFanSpeed = displayedFanSpeed; + data.actualFanSpeed = actualFanSpeed; + data.valveStatus = valveStatus; + data.deviceStatus = deviceStatus; + 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 '05': + { + command_len = 1; + data.targetTemperatureStep = parseInt(commands[i + 1], 16) / 10 + } + break; + case '12': + { + command_len = 1; + data.keepAliveTime = parseInt(commands[i + 1], 16); + } + break; + case '14': + { + command_len = 1; + data.keysLock = toBool(parseInt(commands[i + 1], 16)); + } + break; + case '15': + { + command_len = 2; + data.temperatureRangeSettings = { min: parseInt(commands[i + 1], 16), max: parseInt(commands[i + 2], 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 '2f': + { + command_len = 1; + data.targetTemperature = parseInt(commands[i + 1], 16); + } + break; + case '30': + { + command_len = 1; + data.manualTargetTemperatureUpdate = parseInt(commands[i + 1], 16); + } + break; + case '32': + { + command_len = 1; + data.valveOpenCloseTime = parseInt(commands[i + 1], 16); + } + break; + case '34': + { + command_len = 1; + data.displayRefreshPeriod = parseInt(commands[i + 1], 16); + } + break; + case '36': + { + command_len = 1; + data.extAutomaticTemperatureControl = parseInt(commands[i + 1], 16); + } + break; + case '3e': + { + command_len = 2; + data.extSensorTemperature = parseInt(`${commands[i + 1]}${commands[i + 2]}`, 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.fanSpeed = parseInt(commands[i + 1], 16); + } + break; + case '47': + { + command_len = 1; + data.fanSpeedLimit = parseInt(commands[i + 1], 16); + } + break; + case '49': + { + command_len = 2; + data.ecmVoltageRange = { min: parseInt(commands[i + 1], 16) / 10, max: parseInt(commands[i + 2], 16) / 10 }; + } + break; + case '4b': + { + command_len = 1; + data.ecmStartUpTime = parseInt(commands[i + 1], 16); + } + break; + case '4d': + { + command_len = 1; + data.ecmRelay = parseInt(commands[i + 1], 16); + } + break; + case '4f': + { + command_len = 1; + data.frostProtection = parseInt(commands[i + 1], 16); + } + break; + case '51': + { + command_len = 2; + data.frostProtectionSettings = { threshold: parseInt(commands[i + 1], 16), setpoint: parseInt(commands[i + 2], 16) }; + } + break; + case '55': + { + command_len = 1; + data.allowedOperationalModes = parseInt(commands[i + 1], 16); + } + break; + case '57': + { + command_len = 1; + data.coolingSetpointNotOccupied = parseInt(commands[i + 1], 16); + } + break; + case '59': + { + command_len = 1; + data.heatingSetpointNotOccupied = parseInt(commands[i + 1], 16); + } + break; + case '5b': + { + command_len = 2; + data.tempSensorCompensation = { compensation: parseInt(commands[i + 1], 16), temperature: parseInt(commands[i + 2], 16) }; + } + break; + case '5d': + { + command_len = 1; + data.fanSpeedNotOccupied = parseInt(commands[i + 1], 16); + } + break; + case '5f': + { + command_len = 1; + data.automaticChangeover = parseInt(commands[i + 1], 16); + } + break; + case '61': + { + command_len = 1; + data.wiringDiagram = parseInt(commands[i + 1], 16); + } + break; + case '63': + { + command_len = 1; + data.occFunction = parseInt(commands[i + 1], 16); + } + break; + case '65': + { + command_len = 2; + data.automaticChangeoverThreshold = { coolingThreshold: parseInt(commands[i + 1], 16), heatingThreshold: parseInt(commands[i + 2], 16) }; + } + break; + case '69': + { + command_len = 1; + data.returnOfPowerOperation = parseInt(commands[i + 1], 16); + } + break; + case '6b': + { + command_len = 1; + data.deltaTemperature1 = parseInt(commands[i + 1], 16) / 10; + } + break; + case '6d': + { + command_len = 2; + data.deltaTemperature2and3 = { deltaTemperature2: parseInt(commands[i + 1], 16) * 10, deltaTemperature3: parseInt(commands[i + 2], 16) * 10 }; + } + break; + case '6e': + { + command_len = 1; + data.frostProtectionStatus = parseInt(commands[i + 1], 16); + } + break; + case '70': + { + command_len = 1; + data.occupancySensorStatusSetPoint = parseInt(commands[i + 1], 16); + } + break; + case '71': + { + command_len = 1; + data.occupancySensorStatus = parseInt(commands[i + 1], 16); + } + break; + case '72': + { + command_len = 1; + data.dewPointSensorStatus = parseInt(commands[i + 1], 16); + } + break; + case '73': + { + command_len = 1; + data.filterAlarm = parseInt(commands[i + 1], 16); + } + break; + case '74': + { + command_len = 2; + data.automaticChangeoverMode = { ntcTemperature: parseInt(commands[i + 1], 16), automaticChangeover: parseInt(commands[i + 2], 16) }; + } + break; + case '75': + { + command_len = 1; + data.powerModuleStatus = parseInt(commands[i + 1], 16); + } + 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); + bytes = bytes.slice(-11); + data = handleKeepalive(bytes, data); + } + return { data: data }; + } catch (e) { + throw new Error('Unhandled data'); + } +} \ No newline at end of file diff --git a/vendor/mclimate/fan-coil-thermostat.png b/vendor/mclimate/fan-coil-thermostat.png new file mode 100644 index 0000000000..9816da1c52 Binary files /dev/null and b/vendor/mclimate/fan-coil-thermostat.png differ diff --git a/vendor/mclimate/fan-coil-thermostat.yaml b/vendor/mclimate/fan-coil-thermostat.yaml new file mode 100644 index 0000000000..e56e3288f2 --- /dev/null +++ b/vendor/mclimate/fan-coil-thermostat.yaml @@ -0,0 +1,116 @@ +name: MClimate Fan Coil Thermostat +description: MClimate Fan Coil Thermostat (FCT) is a thermostat compatible with 2-pipe and 4-pipe Fan Coil Units with 4 SPST relays, 1 DPST dry relay and 0-10V input/output. It features a 4.2" e-ink display, digital temperature and humidity sensor, and 4 buttons. + +# Hardware versions (optional, use when you have revisions) +hardwareVersions: + - version: '1.1' + numeric: 1 + +# Firmware versions (at least one is mandatory) +firmwareVersions: + - # Firmware version + version: '1.0' + numeric: 1 + hardwareVersions: + - '1.1' + + # 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: fan-coil-thermostat-profile + lorawanCertified: false + codec: fan-coil-thermostat-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 +# 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: false + +# 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: http://docs.mclimate.eu/mclimate-lorawan-devices/devices/mclimate-fan-coil-thermostat-fct +dataSheetURL: http://docs.mclimate.eu/mclimate-lorawan-devices/devices/mclimate-fan-coil-thermostat-fct +# 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 diff --git a/vendor/mclimate/vicki.js b/vendor/mclimate/vicki.js index 907c5e4825..0fcae4b014 100644 --- a/vendor/mclimate/vicki.js +++ b/vendor/mclimate/vicki.js @@ -291,6 +291,15 @@ function decodeUplink(input) { resultToPass = merge_obj(resultToPass, data); } 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]}` + var fuotaData = { fuota: { fuota_address, fuota_address_raw } }; + resultToPass = merge_obj(resultToPass, fuotaData); + } + break; default: break; } diff --git a/vendor/mclimate/wireless-thermostat.js b/vendor/mclimate/wireless-thermostat.js index 38e6b16652..f8891802ea 100644 --- a/vendor/mclimate/wireless-thermostat.js +++ b/vendor/mclimate/wireless-thermostat.js @@ -119,6 +119,80 @@ function decodeUplink(input) { data.sendTargetTempDelay = parseInt(commands[i + 1], 16) ; } break; + case '38': + { + command_len = 1; + data.automaticHeatingStatus = parseInt(commands[i + 1], 16) ; + } + break; + case '3a': + { + command_len = 1; + data.sensorMode = 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 '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;