From bbdef10b36c2c0bf93c2289384f361c7d19fa950 Mon Sep 17 00:00:00 2001 From: Jedidiah Paterson Date: Wed, 3 Sep 2025 15:00:26 +0100 Subject: [PATCH] Add Pressac IAQ device --- vendor/index.yaml | 11 + .../iaq-sensor-codec.yaml | 8 + .../iaq-sensor-decoder.js | 435 ++++++++++++++++++ .../iaq-sensor-profile.yaml | 47 ++ vendor/pressac-communications/iaq-sensor.jpg | Bin 0 -> 8222 bytes vendor/pressac-communications/index.yaml | 2 + vendor/pressac-communications/logo.png | Bin 0 -> 22337 bytes .../lorawan-indoor-air-quality-sensor.yaml | 82 ++++ 8 files changed, 585 insertions(+) create mode 100644 vendor/pressac-communications/iaq-sensor-codec.yaml create mode 100644 vendor/pressac-communications/iaq-sensor-decoder.js create mode 100644 vendor/pressac-communications/iaq-sensor-profile.yaml create mode 100644 vendor/pressac-communications/iaq-sensor.jpg create mode 100644 vendor/pressac-communications/index.yaml create mode 100644 vendor/pressac-communications/logo.png create mode 100644 vendor/pressac-communications/lorawan-indoor-air-quality-sensor.yaml diff --git a/vendor/index.yaml b/vendor/index.yaml index 85b19da406..3da3908c68 100644 --- a/vendor/index.yaml +++ b/vendor/index.yaml @@ -2160,3 +2160,14 @@ vendors: - id: sensus name: Sensus GmbH Ludwigshafen vendorID: 1170 + + - id: pressac-communications + name: Pressac Communications + description: Sensor Suppliers & IoT Sensor Manufacturers Get the IoT data you need to power your data driven solutions and projects. + logo: logo.png + website: https://www.pressac.com/ + social: + linkedin: https://www.linkedin.com/company/pressac-communications-ltd/ + + + diff --git a/vendor/pressac-communications/iaq-sensor-codec.yaml b/vendor/pressac-communications/iaq-sensor-codec.yaml new file mode 100644 index 0000000000..9dacb990d7 --- /dev/null +++ b/vendor/pressac-communications/iaq-sensor-codec.yaml @@ -0,0 +1,8 @@ +# Uplink decoder decodes binary data uplink into a JSON object (optional) +# For documentation on writing encoders and decoders, see: https://www.thethingsindustries.com/docs/integrations/payload-formatters/javascript/ +uplinkDecoder: + fileName: iaq-sensor-decoder.js + +# Downlink encoder encodes JSON object into a binary data downlink (optional) +downlinkEncoder: + fileName: iaq-sensor-decoder.js diff --git a/vendor/pressac-communications/iaq-sensor-decoder.js b/vendor/pressac-communications/iaq-sensor-decoder.js new file mode 100644 index 0000000000..c95aed0155 --- /dev/null +++ b/vendor/pressac-communications/iaq-sensor-decoder.js @@ -0,0 +1,435 @@ +var notConnectedStr = "Not connected"; + + var messageTypes = { + 0x01: "Boot message", + 0x02: "Sensor data message", + 0x03: "Occupancy data message", + } + + var vocUnits = { + 0: "TVOC μg/m3", + 1: "TVOC ppb", + 2: "VOC Index", + 3: "Reserved", + } + + var tvocEquivalent = { + 0: "Isobutylene", + 1: "Mølhave", + 2: "Ethanol", + 3: "Reserved", + } + + var resetState = { + 1: "Power On", + 2: "Hard Reset", + 3: "Soft Reset", + 4: "Watchdog", + 5: "Brown out", + 6: "Other", + } + + var hardwareRegion = { + 0: "EU868", + 1: "US915", + 2: "AS923", + 3: "AU915", + } + +// Decode uplink function. +// +// Input is an object with the following fields: +// - bytes = Byte array containing the uplink payload, e.g. [255, 230, 255, 0] +// - fPort = Uplink fPort. +// - variables = Object containing the configured device variables. +// +// Output must be an object with the following fields: +// - data = Object representing the decoded payload. +///////////////////////////////////////////////////////////////////////////////// +// Decode Uplink +///////////////////////////////////////////////////////////////////////////////// +function decodeUplink(input) { + var data = {}; + var byte = 0; + + //uncomment if the bytes want to be seen + //data.bytes = input.bytes; + + var productIdRaw = input.bytes[byte++]; + data.productId = "0x"+ productIdRaw.toString(16).toUpperCase(); + + // Message type bit7-bit4, message rev bit3-bit0 + var messageTypeRev = input.bytes[byte++]; + var messageTypeValue = (messageTypeRev >>4) & 0x0f; + + data.message = {} + data.message.type = messageTypes[messageTypeValue]; + data.message.rev = (messageTypeRev & 0x0f); + + // Battery status + var batteryInfo = input.bytes[byte++]; + // If 0 means lined powered + if(batteryInfo == 0){ + data.batteryVoltage = "External powered"; + } + else if (batteryInfo == 0xff){ + data.batteryVoltage = "Not measured"; + } + else{ + // convert the voltage in 0.2V steps + data.batteryVoltage = convertRange(batteryInfo, 1, 241, 0, 48); + } + + // Depending on the message type it is decoded differently + // Boot Message + if(messageTypeValue == 1){ + // Get the firmware version + var firmwareVersionValue = input.bytes[byte++]; + firmwareVersionValue = (firmwareVersionValue << 8) | input.bytes[byte++]; + + data.firmwareVersion = (((firmwareVersionValue >> 12) & 0x0f) + '.' + ((firmwareVersionValue >> 8) & 0x0f) + '.' + ((firmwareVersionValue >> 4) & 0x0f) + '.' + (firmwareVersionValue & 0x0f)); + + // Reset reason + data.resetReason = resetState[input.bytes[byte++]]; + + // Hardware region + data.hardwareRegionSelection = hardwareRegion[input.bytes[byte++]]; + + // Sensors present + var sensorAvailableValue = input.bytes[byte++]; + data.isSensorsAvailable = {}; + data.isSensorsAvailable.temphumid = (sensorAvailableValue & (1 << 0)) !== 0 ? true: false; + data.isSensorsAvailable.tvoc = (sensorAvailableValue & (1 << 1)) !== 0 ? true: false; + data.isSensorsAvailable.co2 = (sensorAvailableValue & (1 << 2)) !== 0 ? true: false; + data.isSensorsAvailable.pm = (sensorAvailableValue & (1 << 3)) !== 0 ? true: false; + data.isSensorsAvailable.lux = (sensorAvailableValue & (1 << 4)) !== 0 ? true: false; + data.isSensorsAvailable.soundLevel = (sensorAvailableValue & (1 << 5)) !== 0 ? true: false; + data.isSensorsAvailable.pir = (sensorAvailableValue & (1 << 6)) !== 0 ? true: false; + + // Reading Interval + var readIntervalValue = input.bytes[byte++]; + data.readInterval ={}; + data.readInterval.configuration = (readIntervalValue & (1 << 0)) !== 0 ? 'Network' : 'Dip Switch'; + data.readInterval.unit = "Minutes"; + data.readInterval.value = ((readIntervalValue >> 1) & 0xFF); + + // PM Sensor + if(data.isSensorsAvailable.pm == true){ + var pmMaskValue = input.bytes[byte++]; + data.particuleMatter = {}; + data.particuleMatter.isAutoCleanIntervalSet = (pmMaskValue & (1 << 0)) !== 0 ? true: false; + // Clean is not disabled, so show the interval period + if(data.particuleMatter.isAutoCleanIntervalSet == true){ + // Clean Interval + data.particuleMatter.autoCleanInterval = {}; + data.particuleMatter.autoCleanInterval.value = ((pmMaskValue >> 2) & 0x07); + data.particuleMatter.autoCleanInterval.units = "Days"; + } + } + + // CO2 sensor + if(data.isSensorsAvailable.co2 == true){ + data.co2 = {}; + + // Fresh Air + var co2FreshMaskValue = input.bytes[byte++]; + co2FreshMaskValue = (co2FreshMaskValue << 8) | input.bytes[byte++]; + data.co2.hasManualCalibrationPerformed = (co2FreshMaskValue & (1 << 15)) !== 0 ? true : false; + data.co2.freshAirBackgroundLevel = {}; + data.co2.freshAirBackgroundLevel.value = (co2FreshMaskValue & 0x7FFF); + data.co2.freshAirBackgroundLevel.units = "PPM"; + + // Indoor Air + var co2IndoorMaskValue = input.bytes[byte++]; + co2IndoorMaskValue = (co2IndoorMaskValue << 8) | input.bytes[byte++]; + data.co2.isAutoCalibrationEnabled = (co2IndoorMaskValue & (1 << 15)) !== 0 ? true : false; + data.co2.indoorAirBackgroundLevel = {}; + data.co2.indoorAirBackgroundLevel.value = (co2IndoorMaskValue & 0x7FFF); + data.co2.indoorAirBackgroundLevel.units = "PPM"; + } + + // PIR + if(data.isSensorsAvailable.pir == true){ + data.pir = {}; + data.pir.AbsenceTimeOut = {}; + data.pir.AbsenceTimeOut.value = input.bytes[byte++]; + data.pir.AbsenceTimeOut.units = "Minutes"; + data.pir.RepeatedTimeOut = {}; + data.pir.RepeatedTimeOut.value = input.bytes[byte++]; + data.pir.RepeatedTimeOut.units = "Minutes"; + } + + // Temperature and humidity + if(data.isSensorsAvailable.temphumid == true){ + data.temperatureOffset = {}; + // Temperature Offset + var temperatureOffsetRaw = input.bytes[byte++]; + data.temperatureOffset.value = temperatureOffsetRaw; + data.temperatureOffset.scaled = ((0.25*temperatureOffsetRaw) - 5); //0..40 is -5..+5 + data.temperatureOffset.units = "°C"; + // Humidity Offset + data.humidityOffset = {}; + var humidityOffsetRaw = input.bytes[byte++]; + data.humidityOffset.value = humidityOffsetRaw; + data.humidityOffset.units = "%"; + data.humidityOffset.scaled = ((0.5*humidityOffsetRaw) - 5); //0..20 is -5..+5 + } + + // VOC + if(data.isSensorsAvailable.tvoc == true){ + var vocMaskValue = input.bytes[byte++]; + data.voc = {}; + data.voc.Unit = vocUnits[(vocMaskValue) >> 4]; + data.voc.Equivalent = tvocEquivalent[(vocMaskValue & 0x0F)]; + } + } + + // Environmental data + else if(messageTypeValue == 2){ + data.dataAge = input.bytes[byte++]; + + // Sensors present + var sensorAvailableValue = input.bytes[byte++]; + data.isSensorsAvailable = {}; + data.isSensorsAvailable.temphumid = (sensorAvailableValue & (1 << 0)) !== 0 ? true : false; + data.isSensorsAvailable.tvoc = (sensorAvailableValue & (1 << 1)) !== 0 ? true : false; + data.isSensorsAvailable.co2 = (sensorAvailableValue & (1 << 2)) !== 0 ? true : false; + data.isSensorsAvailable.pm = (sensorAvailableValue & (1 << 3)) !== 0 ? true : false; + data.isSensorsAvailable.lux = (sensorAvailableValue & (1 << 4)) !== 0 ? true : false; + data.isSensorsAvailable.soundLevel = (sensorAvailableValue & (1 << 5)) !== 0 ? true : false; + data.isSensorsAvailable.pir = (sensorAvailableValue & (1 << 6)) !== 0 ? true : false; + + // Sensor data, Only if available + if(data.isSensorsAvailable.temphumid == true){ + data.temperature = {}; + data.temperature.value = convertTemp(input.bytes[byte++]); + data.temperature.units = "°C"; + data.humidity = {}; + data.humidity.value = convertHum(input.bytes[byte++]); + data.humidity.units = "%"; + + } + + if(data.isSensorsAvailable.pm == true){ + // Convert PM10 + var pmRaw = input.bytes[byte++] << 8 | input.bytes[byte]; + data.particulateMatter = {}; + data.particulateMatter.pm10 = convertPm((pmRaw & 0xFF80) >> 7); + // Convert PM4 + pmRaw = input.bytes[byte++] << 8 | input.bytes[byte]; + data.particulateMatter.pm4 = convertPm((pmRaw & 0x7FC0) >> 6); + // Convert PM2.5 + pmRaw = input.bytes[byte++] << 8 | input.bytes[byte]; + data.particulateMatter.pm2_5 = convertPm((pmRaw & 0x3FE0) >> 5); + // Convert PM1.0 + pmRaw = input.bytes[byte++] << 8 | input.bytes[byte++]; + data.particulateMatter.pm1_0 = convertPm((pmRaw & 0x1FF0) >> 4); + // Units + data.particulateMatter.units = "µg/m³"; + } + + if(data.isSensorsAvailable.soundLevel == true){ + data.soundLevel = {}; + data.soundLevel.value = convertSound(input.bytes[byte++]); + data.soundLevel.units = "dBA"; + } + + if(data.isSensorsAvailable.lux == true){ + data.illumination = {}; + data.illumination.value = convertLux(input.bytes[byte++] << 8 | input.bytes[byte++]); + data.illumination.units = "lx"; + } + + if(data.isSensorsAvailable.co2 == true){ + data.co2 = {}; + data.co2.value = convertco2(input.bytes[byte++] << 8 | input.bytes[byte++]); + data.co2.units = "PPM"; + } + + if(data.isSensorsAvailable.tvoc == true){ + var vocRaw = input.bytes[byte++] << 8 | input.bytes[byte++]; + data.voc = {} + data.voc.value = convertVoc(vocRaw & 0x3FFF); + + if (data.voc === notConnectedStr) { + data.voc.units = notConnectedStr; + } else { + data.voc.units = vocUnits[(vocRaw & 0xC000) >> 14]; + } + } + } + + // occupancy data + else{ + data.dataAge = input.bytes[byte++]; + var occupancyValue = input.bytes[byte++]; + + data.occupancyDetected = ((occupancyValue &0x01) == 0) ? 'Vacant' : 'Occupied'; + } + + // Return the data structure + return { + data: data, + }; +} + +// Encode downlink function. +// +// Input is an object with the following fields: +// - data = Object representing the payload that must be encoded. +// - variables = Object containing the configured device variables. +// +// Output must be an object with the following fields: +// - bytes = Byte array containing the downlink payload. +///////////////////////////////////////////////////////////////////////////////// +// Decode Downlink +///////////////////////////////////////////////////////////////////////////////// +function encodeDownlink(input) { + // Initialize the output object + var data = {}; + + if (input.fport == 60){ + data.message = {}; + + // Config message + if(input.bytes[0] == 0x01){ + data.message.type = "Configuration Message"; + data.message.version = input.bytes[1]; + + // Reading Interval + var readIntervalValue = input.bytes[2]; + data.readInterval ={}; + data.readInterval.configuration = (readIntervalValue & (1 << 0)) !== 0 ? 'Network' : 'Dip Switch'; + data.readInterval.unit = intervalUnit[(readIntervalValue & 0x06)]; + data.readInterval.value = ((readIntervalValue & 0xf8) >> 3); + + // Particule Matter + var pmMaskValue = input.bytes[3]; + data.particuleMatter = {}; + // Enabled Pm size + data.particuleMatter.isEnabled = {}; + data.particuleMatter.isEnabled._1um = (pmMaskValue & (1 << 4)) !== 0 ? true :false; + data.particuleMatter.isEnabled._2_5um = (pmMaskValue & (1 << 5)) !== 0 ? true :false; + data.particuleMatter.isEnabled._4um = (pmMaskValue & (1 << 6)) !== 0 ? true :false; + data.particuleMatter.isEnabled._10um = (pmMaskValue & (1 << 7)) !== 0 ? true :false; + // Clean Interval + data.particuleMatter.cleanInterval ={}; + data.particuleMatter.cleanInterval.value = ((pmMaskValue & 0x0e) >> 1); + data.particuleMatter.cleanInterval.units = "Days"; + // Clean Performed + data.particuleMatter.hasCleaned = (pmMaskValue & (1 << 0)) !== 0 ? true :false; + + // Co2 + data.co2 = {}; + // Fresh Air + var co2FreshMaskValue = input.bytes[4]; + co2FreshMaskValue = (co2FreshMaskValue << 8) | input.bytes[5]; + data.co2.hasManualCalibrationPerformed = (co2FreshMaskValue & (1 << 15)) !== 0 ? true :false; + data.co2.freshAirBackgroundLevel = {}; + data.co2.freshAirBackgroundLevel.value = (co2FreshMaskValue & 0x7FFF); + data.co2.freshAirBackgroundLevel.units = "PPM"; + // Indoor Air + var co2IndoorMaskValue = input.bytes[6]; + co2IndoorMaskValue = (co2IndoorMaskValue << 8) | input.bytes[7]; + data.co2.isAutoCalibrationEnabled = (co2IndoorMaskValue & (1 << 15)) !== 0 ? true :false; + data.co2.indoorAirBackgroundLevel = {}; + data.co2.indoorAirBackgroundLevel.value = (co2IndoorMaskValue & 0x7FFF); + data.co2.indoorAirBackgroundLevel.units = "PPM"; + + // PIR + data.pirAbsenceTimeOut = {}; + data.pirAbsenceTimeOut.value = input.bytes[8]; + data.pirAbsenceTimeOut.units = "Minutes"; + } + + // PM Clean Sensor + else if (input.bytes[0] == 0x02){ + data.message.type = "PM Sensor Clean"; + data.message.version = input.bytes[1]; + data.pmTriggerValue = input.bytes[2]; + } + + // Unknown message type + else{ + data.message.type = "Unknown message type"; // Handle unexpected types + } + + // Return the decoded data + return { + data: data, + }; + + } + // Must be a server downlink message + else{ + return { + bytes: [225, 230, 255, 0] + }; + } + +} + + +///////////////////////////////////////////////////////////////////////////////// +// Value Conversion functions +///////////////////////////////////////////////////////////////////////////////// +function convertRange(num, inMin, inMax, outMin, outMax) { + out = outMin + ((num - inMin) / (inMax - inMin) * (outMax - outMin)); + return parseFloat(out.toFixed(2)); +} + +function convertTemp(num) { + if (num === 0xFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 240, -10, 50); + } +} + +function convertHum(num) { + if (num === 0xFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 200, 0, 100); + } +} + +function convertPm(num) { + if (num === 0x1FF) { + return notConnectedStr; + } else { + return num; + } +} + +function convertSound(num) { + if (num === 0xFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 250, 0, 125); + } +} + +function convertLux(num) { + if (num === 0xFFFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 20000, 0, 20000); + } +} + +function convertco2(num){ + if (num === 0xFFFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 5000, 0, 5000); + } +} + +function convertVoc(num) { + if (num === 0x3FFF) { + return notConnectedStr; + } else { + return convertRange(num, 0, 5000, 0, 5000); + } +} \ No newline at end of file diff --git a/vendor/pressac-communications/iaq-sensor-profile.yaml b/vendor/pressac-communications/iaq-sensor-profile.yaml new file mode 100644 index 0000000000..79682c8707 --- /dev/null +++ b/vendor/pressac-communications/iaq-sensor-profile.yaml @@ -0,0 +1,47 @@ +# LoRaWAN MAC version: 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 or 1.1 +macVersion: '1.0.1' +# LoRaWAN Regional Parameters version. Values depend on the LoRaWAN version: +# 1.0: TS001-1.0 +# 1.0.1: TS001-1.0.1 +# 1.0.2: RP001-1.0.2 or RP001-1.0.2-RevB +# 1.0.3: RP001-1.0.3-RevA +# 1.0.4: RP002-1.0.0 or RP002-1.0.1 +# 1.1: RP001-1.1-RevA or RP001-1.1-RevB +regionalParametersVersion: 'TS001-1.0.1' + +# Whether the end device supports join (OTAA) or not (ABP) +supportsJoin: true +# If your device is an ABP device (supportsJoin is false), uncomment the following fields: +# RX1 delay +#rx1Delay: 5 +# RX1 data rate offset +#rx1DataRateOffset: 0 +# RX2 data rate index +#rx2DataRateIndex: 0 +# RX2 frequency (MHz) +#rx2Frequency: 869.525 +# Factory preset frequencies (MHz) +#factoryPresetFrequencies: [868.1, 868.3, 868.5, 867.1, 867.3, 867.5, 867.7, 867.9] + +# Maximum EIRP +maxEIRP: 14 +# Whether the end device supports 32-bit frame counters +supports32bitFCnt: true + +# Whether the end device supports class B +supportsClassB: false +# If your device supports class B, uncomment the following fields: +# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds) +#classBTimeout: 60 +# Ping slot period (seconds) +#pingSlotPeriod: 128 +# Ping slot data rate index +#pingSlotDataRateIndex: 0 +# Ping slot frequency (MHz). Set to 0 if the band supports ping slot frequency hopping. +#pingSlotFrequency: 869.525 + +# Whether the end device supports class C +supportsClassC: false +# If your device supports class C, uncomment the following fields: +# Maximum delay for the end device to answer a MAC request or confirmed downlink frame (seconds) +#classCTimeout: 60 diff --git a/vendor/pressac-communications/iaq-sensor.jpg b/vendor/pressac-communications/iaq-sensor.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cad565d24470341ce917cbf434af530015c7a82f GIT binary patch literal 8222 zcmdUUXH-*Nx9(18p_))bl_El@p-Qm;QUsBgP(za@y-61o2vwwmKtPZx9qAoZIw-wK zN2(O1NfSgk0pIUE-yP$Q@5jC8&soXXbL~0jGh5bPduH$RiSu~?s-mc@2!KEU0K$EM z^E2S;T_=afE*7q?7LQoXyjX1?TUhbCSeXCKJf8-F0OHF*LP|xB>h#za~B19L(Y&Hurk| zzd4}jUX1MlpYz~9ta+)To?g7hTNFnX|L_*tUL%i(n85}f_bX!l#dYp?eNKHm>OaUl zTjG;0^EdnPDo4Mf&{wh_fSXd>W{O+C=HCJe$$l51AX5g{PH2UUlq|B=vOvY;k4(Zf zb=ed$PO^^CW%OcwA%OXB8K^Banhi2WvQbPVv0OiH-Q-4);(qwIOv5YUZ_(j zA`1(x`>+D`$->|E1-9*{E33?@YEs^o=PKPMO)xN zU-!2!Gl%x^`THJ|D=zC@HHX5Lv9%?iPM-P1M$v}e+B}+N{ev*omfW-Gh`w%rFqSv6 z>FzC(ty;Y~5NEi89d1&Y=KrY1?`A&UJ8@P!*XY}1#@R;} z(_9F>>0&vd)s(B1hYf%9aDn0$y}2PG`?meW&2*LzN|Qg&0l(=A50z<23f-lXFBVmQ zYvN31Llg@OE_^FtpWixLP2ZQ=+^osQ_MJo*{7Vbeg-ab;(tsFv*}o@zOn>7k>VR*v zwyE1Ez5btFVWD3U8SIWq7vMoY`MGxBQ(s!!y?-|Fbhv}d zn(iX&f4jTk^g&>}%e3+Sg#Di^{NH8ZQOtz^WPQ2Sfvh1Hryy(Mdl!^OmR3C!N67&N z5G#&KJz|dwQkKD8jg>HNu&_FgwfU$S=%v1pInZ|#$7JAUb_Mj^ag>9&8R^J9D-rg~ z(s%x0|XO?rswh+k3nYj$nToch;5Dkcl%lNww0Nnwd18aha zP?kH;IKuKG7p(BEt#Er`-oV0YAz^ZBN0g66p$>1+Gtpi;^uc{E@0_>&V2X6ohqs(O zsQl36S!1h$J1JVEtMom-^YBRa(bXOIm6hhtw{*{#SxtO=HpSM-lcK5E@|(=ULY`Hc3ImTp3J3gm^?%I3vVC zt%Fq^!|>2jKdtYd2uUoqp3wVy`foWo2x3=2R-N=DQJ$YIL$h8jo&${sNxE=H@zoQx zp>}%vn+LDQ-~?xW#h;c^S0y|wb*WMp;(2aH)H84QKJZa^TWqy5dc6}56mZ3Aj_T44 zKWVcg5z1Dk`M^m?fR8goK;7IupEpBmFF8kyQMib7FW7op`_*)hMJl|1M_Ze??KTV2 zLe*R1Zu-s4S#!Cc&O7HosL-N4`ti={Uifp*pK#&R%-Mk8oyD`OKVKIssos=q)(XT# z`c|^p^^5RrijHSfSWd$23dI?cpX_W*QPR?W(0uCghO%AA{v62F|I8EwGYOpRgsWbs z4bHUIrxFq#A*(+OKFw+L|wlin&NOKV=mxp_H_#ImnX%g_fCXl)A_P*iHaTtna?}$YtnOu zkUrv1)zuGMj0MjznG26-&oQQXEb&cjhgUlApES3W7jE3-+~J(~()s1hO6q%$R}`*T zSs>;WoMz*gJ{lNo!Oy1x~e`~)tK?LGU>i>&GoB2zrRY? z8}i4D2LU5@Q*O+m>olhxil6=XU1Ta{$8VFr$i>$n7JN4x=6q+}mYccj1m5SHnV;F} z2g5%NQm~rQE|`Nj-qe2t;N6qxpbIPG0~=f>%Wy;EMQ>D0uznQPgt}IARUTS6VD@Eb zX|FrNla{x+dEkRY)wER?s_@odq^gGvx&-T1$DM`NuiQFrJZl`(Xww>?h!bl-^WN@(g9o!(T0aJ|?K`1&)ra`jmrMPEeOyOsLZ z(;WLL?7{v^6Xjtsx&G0S-^J)AwOB+j@v})y@)Ke_bRK=#3pE0a%&k<@5V$-$O|U65 zU5&GN{Pn)r6E|aNMVZ47gyeg{b1@~`uOhmz^v*-~>-X;XhR4#rA?HQuf3vh?K}Fia z5yM$}UUQE5Bon*7T#exoggK@tJB{YlZK4H@n%=s-qijyf(YfltAMZ5|BIU@%W`B)` zA~bcWk%=o|NZs5#8xoOK;sUqXAVm9@O~M7+>auN$rj_K_qXpz|{v||%$k59i(K<8{<)1aCSQ3p^Rw#3%vNoKKlKbRaex~$GAlnP&H0G8! zvHhBZ=K$*00UnI@P1C-&bl(=m4C7w(FxW9GVK%mW{@q@a&!;de+vbP9lKCX@vp#0x z1Chf~Ak9ynHdNKrroMXj-^t&V9Tg0X)Ckbl7N5Hc$;##GoG%4gmsF#IY1^DuFpq>R zy{6FQ=63{g)P7&x_{}j^!^B)PO1#of;x*PW)!uw&B*tqMEOJL#$;#@6WU`VaiAeHO zRa_P@NU$j`jbQWPXtj~5-1&*U_?j}8g4oqo(hra}A{qnn-i@gw+7oH452l@*xAo^%iLKEPbXo};8kPTU?r4~uA1SxT_0^jg zFkENI9{VV)SNZ*w1!7p=eCl(M92+zg7po;)=a$62IfC-F?i+>5hZ+fw3Z=Pj8+t!3 zL7qA|#p~MIsA_Er+23F`IrRTpQPXc*=dky-4q{hV)Ie<*?afKvBfZT$zyb0ppf}>t z*j++s&St19?|pv6aYrY6Udhgk)fkeboX=E)=6~Lm+6@rCrs3fiN^8o{Pw3{)LsWiG zombCln-)*R1w=VQ)<)8)tP$_+ksJW&##QeGIo5CJH(p4CMp4IZr(_MfT%sJX~Fq<2_8W?>OrJ z8Mt4E&)a#eQ;t)rnmesOZ9Tpy$4J;wDPt_RB)=DrnG3cc(9M)m<5|n-@@-Ls9(zl} zo_LwdCQR&m%~o&7YkZ7=TO_J56%p5${^$d-O56y`?YXKy19z#KU-K4P*N3I%RL3S5 zcD?((x=GEbxT)RP#=$*0CGMeBH1$BpWv#58G4h?v!9SJgn^x1bnq<$HHQgc4!HrC4 zs5~#d`A7nHr`&a_$66CF)XGe4U!7!*7d)Je@BO4j-`8)cJ{j=Um*B$lpN034Mmp8niF2RS>qtlis+S-*eWTG0P5=fwCcm=C)5?FW-yn1hpq157HMbs`J zQ2M@p_*44&mkYRu=Nd1wS>?!$yG~U(hE6>aHG-eCGS$lZNfHiK(+&{7<@0o2TeOEP zW&PM;$x#VcwJJr}CJfm9NV)y-jTVIOHtA(ZB(3Gc49*2gIW{4h`5$vrvqn_{z9_4N z4HxRUaR`kvi}6lZBqyr`O4j#&V&tYzj`=A*JUl#D%uCOfM=r6StyzT-p-gzz>@<+i z#!C8{L(BGE!bi)2ikGb#8C6};t+a`WiAkn<0XQFBIpo}<<{W&C4^*BBQJ}<6$mhPN zDS8`SIl^Z|+ZV7ou|PG8v?4UECh9vBWU;LtIHV>01@f*Oa~ktYI>R<7R*S(-o2=Kl`E)Z1PYO+zUqgEj8kLS3W2R0E0pJ03jF*#=GoY0T`Q* zEEHwx%!*X^kIgh0k|~dA$ynI=r%#2R1Ks?x@vMcVKd2l)^mdedQ?*}`9d%r2JpyzZ zKSZ0X&neK!r`W>_Z+{BYK$*xDr{XnnlpeYS-$_Bli;D53mSf=Ed4$>rJzP*^{@Ef;Rp~8 z?Zkc!E__yT0i{J21+Y##nTDNWRUsLWxEKozPcXr9n0U}`#w$gg`|LgJbkB637}4#C zEOwfV%mhfnq+?8aPTu06eCYCE^6I6eD6r9KLnJ{(qXJQQ3n0o2{SFU$Fiv`wLHWq9 z*>Qxt1#_Q~wFP^?cnL8l(SA#H4%j6X)vih({tOl!iC((109J%RO0cI?r<8*(tGKT76+^(JHu?(XhQaDq8S2?w<@9{EjlN>Kzft zw$CMV^1o#xqxK{w5FZjV-+j`1?2*vIn}rwUuVTyY$E3~jp+ZfXlHLCo-yR0meMnp@)A_|=#2efO(?;LCem zjbIhln2{^d%|B zPIcs66q_O^W4okNvj2>Z?jdIbBvj?cPP`BSNNYQ8kGSx2%7<(ET+G_qU-%SE2J?yN zUMrSSDHqi~VvJ(Ptn}@YQ{A&;>$c^-ZZw#8`??p6e(?-7A!KC245Js;=PL4)CyUzJ zLG+hokiTQ$93+5UO0jF6O0?em-TwO*ZhX7ItYuCdD1x5^~l;0ph3N4O3M1t6#0%3OVYe z+hlh90Gs}aiZ%p~(-Ea*FYxVZlF_GZUOnIT9@D!v21kNoY9-%bdN0cHQ%>t$^JPMY zSG-L^Im~nM`BC^hGzJf`P`Q9A(z>-V#R1)DhTxoOkLK#_d9;lGzK2k>T$Du4t?Oo` z@+dEU{IH0RbHx-GAaWujqT8S9-iBeFP-@Lx>FsMe>t%XWxmE<;1+pqFAWwv4ne&w! z%X7M)6{x0J0mP!GiPwBqSF43!ViT4EA)8# zt4ybDU6*6GY#M*2K=k0nBan9v!6fImy6!6OCyp$bP8u!aLK4h%AcF+V!KKY2wx~VC zdON05=;sV6Ov---9*7KGRx!;cC9=5ce(f4QYok_IL%qxVawLzN?iM1%H7;ZjUmJW5 zAYD~j1`kpaO}HF1w>4(q$i~AlB|YwJ6}CmyE2LvD5ySCLlV-9l+KE40aZi+NRCPlc z-(+tFWY_BBO%@BW=I9kZuXePOr{;M-IV51t7n@^8@*JupljquWMPGRHku)75mKOLp zb9f-ggh%LnoJjJB`b z7P60uqC$NT5%*&5lHDO6j%A-

mp5vKbEK!B0%2OQg2f;xZ>7Sa@MU0=0)!iFxIc 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 literal 0 HcmV?d00001 diff --git a/vendor/pressac-communications/lorawan-indoor-air-quality-sensor.yaml b/vendor/pressac-communications/lorawan-indoor-air-quality-sensor.yaml new file mode 100644 index 0000000000..e849956787 --- /dev/null +++ b/vendor/pressac-communications/lorawan-indoor-air-quality-sensor.yaml @@ -0,0 +1,82 @@ +name: LoRaWAN Indoor Air Quality Sensor +description: Indoor air quality sensor accurately measures the environmental conditions providing essential data for IoT platforms for healthier, more efficient buildings. + +# Hardware versions (optional, use when you have revisions) +hardwareVersions: + - version: '1.0.0.0' + numeric: 1 + +# Firmware versions (at least one is mandatory) +firmwareVersions: + - # Firmware version + version: '1.0.0.0' + numeric: 1 + + hardwareVersions: + - '1.0.0.0' + + # Firmware features (optional) + # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how + # often he device sends a message). + features: + - remote rejoin + - transmission interval + + # 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: + # Optional identifier of the vendor of the profile. When you specify the vendorID, the profile is loaded from + # the vendorID's folder. This allows you to reuse profiles from module or LoRaWAN end device stack vendors. + # If vendorID is empty, the current vendor ID is used. In this example, the vendorID is the current vendor ID, + # which is verbose. + vendorID: pressac-communications + # Identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters) + id: iaq-sensor-profile + lorawanCertified: false + codec: iaq-sensor-codec + + +# Sensors that this device features (optional) +# Valid values are: +# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity, current, digital input, +# digital output, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, hall effect, humidity, iaq, infrared, leaf wetness, level, +# light, lightning, link, magnetometer, moisture, motion, nfc, no, no2, o3, occupancy, optical meter, particulate matter, ph, pir, +# pm2.5, pm10, potentiometer, power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, reed switch, rssi, +# sap flow, smart valve, smoke, snr, so2, solar radiation, sound, strain, surface temperature, switch, temperature, tilt, time, turbidity, +# tvoc, uv, vapor pressure, velocity, vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed. +sensors: + - co2 + - temperature + - humidity + - tvoc + - pm2.5 + - pm10 + +# Dimensions in mm (optional) +# Use width, height, length and/or diameter +dimensions: + width: 42 + length: 110 + height: 100 + +# Operating conditions (optional) +operatingConditions: + # Temperature (Celsius) + temperature: + min: -10 + max: 55 + +# Key provisioning (optional) +# Valid values are: custom (user can configure keys), join server and manifest. +keyProvisioning: + - join server + +# Product and data sheet URLs (optional) +productURL: https://www.pressac.com/environment-sensors/lorawan-indoor-air-quality-sensors/ +dataSheetURL: https://support.pressac.com/hubfs/Datasheets%202024/Datasheet%20-%20LoRaWAN%20Indoor%20Air%20Quality%20Sensor.pdf + +# Photos +photos: + main: iaq-sensor.jpg # Image needs to have a transparent background