Indeklimasensor ERS CO2
Info | |
---|---|
Produktnavn | Indeklimasensor ERS CO2 |
Sensortype | |
Modelnavn | Indeklima Elsys ERS CO2 |
Producent | Elsys |
Kort beskrivelse | Indeklimasensor med bl.a. temperatur, co2, bevægelse. |
Netværk | LoRaWAN |
Dokumentation | https://www.elsys.se/en/ers/ |
Producentens hjemmeside | https://www.elsys.se/en/ |
Anvendes i projekterne |
Indholdsfortegnelse
Brugeroplevelse: Erfaring og konklusion på ERSC02
Ballerup Kommune har testet sensorer i forskellige lokaler hvoraf ERSCO2 indgår i rækken af test-devices. Devicet er i 2020 også testet jævnfør SAnD´s køleskabscase, primært med henblik på temperaturmåling.
Konklusion maj 2020 er:
- devicet kører stabilt
- kører langt på batteriet
- dokumentation(dekodning af hex-data i database) er rigtig god
- dekodningscript (javascript) af hex-data til anvendelse på netværksserver er tilgængelig
- kommunikation og assistance med producent er god
Devicet er i den prisdyre ende og bør derfor anvendes på de klassiske indendørscases, hvor der måles på alle parametre som devicet understøtter. Ballerup Kommune har i 2019/2020 testet dem i kommunens køleskabe. Der kan være udfordring med at data kan opsamles af udendørs gateways, da signalstyrken er noget mindre ved data-transfer inde fra køleskab. Derfor har vi suppleret med indendørs gateways (eks. Kerlinks IfemtoCell) i de akutelle bygninger hvor devicet er placeret.
Tilslutning og konfiguration af device til netværksserver
Guiden her anvender Chirpstack som eksempel, men kan også anvendes på andre platforme.
Elsys har lanceret deres egen mobil-app "Sensor Settings"(android & iOS) til konfiguration og opkobling til brugerens netværksserver.
Kræver at brugerens tablet/smartpohone understøtter NFC.
Med appen kan brugeren:
- aflæse devicets tilslutningsnøgler
- definere frekvens for upload af data - dvs. hvor ofte skal data transmitteres fra device
- kalibrere sensor
- styre den infrarøde sensors følsomhed
- bestemme OTAA-tilslutning (foretrukket)
Workflow: Konfiguration ved brug af NFC og app til Chirpstack:
- aflæs DevEUI på device (står også bagpå)
- aktiver OTAA (Under "Sensor Keys"), notér AppKey og skriv("Write") til device
- Indtast AppKey på Chirpstack under "Application Server" --> "Keys (OTAA)"
- IKKE udfylde "Gen Appliation Key" ud
- I Chirpstack - hold øje med fanen "Activation" og at devicet faktisk er aktiveret.
Dekodning af payload på netværksserver - Chirpstack
Dekodnings-scriptet fra Elsys tilføjes under "Device-profiles" ---> "Codec" under "Payload codec".
Husk at tilknytte dit device til denne "Device-profile". Verificér at payload er dekodet og kommer ud i "oversat" format under dit device("LORAWAN FRAMES")
var TYPE_TEMP = 0x01; //temp 2 bytes -3276.8°C -->3276.7°C
var TYPE_RH = 0x02; //Humidity 1 byte 0-100%
var TYPE_ACC = 0x03; //acceleration 3 bytes X,Y,Z -128 --> 127 +/-63=1G
var TYPE_LIGHT = 0x04; //Light 2 bytes 0-->65535 Lux
var TYPE_MOTION = 0x05; //No of motion 1 byte 0-255
var TYPE_CO2 = 0x06; //Co2 2 bytes 0-65535 ppm
var TYPE_VDD = 0x07; //VDD 2byte 0-65535mV
var TYPE_ANALOG1 = 0x08; //VDD 2byte 0-65535mV
var TYPE_GPS = 0x09; //3bytes lat 3bytes long binary
var TYPE_PULSE1 = 0x0A; //2bytes relative pulse count
var TYPE_PULSE1_ABS = 0x0B; //4bytes no 0->0xFFFFFFFF
var TYPE_EXT_TEMP1 = 0x0C; //2bytes -3276.5C-->3276.5C
var TYPE_EXT_DIGITAL = 0x0D; //1bytes value 1 or 0
var TYPE_EXT_DISTANCE = 0x0E; //2bytes distance in mm
var TYPE_ACC_MOTION = 0x0F; //1byte number of vibration/motion
var TYPE_IR_TEMP = 0x10; //2bytes internal temp 2bytes external temp -3276.5C-->3276.5C
var TYPE_OCCUPANCY = 0x11; //1byte data
var TYPE_WATERLEAK = 0x12; //1byte data 0-255
var TYPE_GRIDEYE = 0x13; //65byte temperature data 1byte ref+64byte external temp
var TYPE_PRESSURE = 0x14; //4byte pressure data (hPa)
var TYPE_SOUND = 0x15; //2byte sound data (peak/avg)
var TYPE_PULSE2 = 0x16; //2bytes 0-->0xFFFF
var TYPE_PULSE2_ABS = 0x17; //4bytes no 0->0xFFFFFFFF
var TYPE_ANALOG2 = 0x18; //2bytes voltage in mV
var TYPE_EXT_TEMP2 = 0x19; //2bytes -3276.5C-->3276.5C
var TYPE_EXT_DIGITAL2 = 0x1A; // 1bytes value 1 or 0
var TYPE_DEBUG = 0x3D; // 4bytes debug
function bin16dec(bin) {
var num=bin&0xFFFF;
if (0x8000 & num)
num = - (0x010000 - num);
return num;
}
function bin8dec(bin) {
var num=bin&0xFF;
if (0x80 & num)
num = - (0x0100 - num);
return num;
}
function hexToBytes(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
function DecodeElsysPayload(data){
var obj = new Object();
for(i=0;i<data.length;i++){
//console.log(data[i]);
switch(data[i]){
case TYPE_TEMP: //Temperature
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
obj.temperature=temp/10;
i+=2;
break
case TYPE_RH: //Humidity
var rh=(data[i+1]);
obj.humidity=rh;
i+=1;
break
case TYPE_ACC: //Acceleration
obj.x=bin8dec(data[i+1]);
obj.y=bin8dec(data[i+2]);
obj.z=bin8dec(data[i+3]);
i+=3;
break
case TYPE_LIGHT: //Light
obj.light=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_MOTION: //Motion sensor(PIR)
obj.motion=(data[i+1]);
i+=1;
break
case TYPE_CO2: //CO2
obj.co2=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_VDD: //Battery level
obj.vdd=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_ANALOG1: //Analog input 1
obj.analog1=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_GPS: //gps
obj.lat=(data[i+1]<<16)|(data[i+2]<<8)|(data[i+3]);
obj.long=(data[i+4]<<16)|(data[i+5]<<8)|(data[i+6]);
i+=6;
break
case TYPE_PULSE1: //Pulse input 1
obj.pulse1=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_PULSE1_ABS: //Pulse input 1 absolute value
var pulseAbs=(data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4]);
obj.pulseAbs=pulseAbs;
i+=4;
break
case TYPE_EXT_TEMP1: //External temp
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
obj.externalTemperature=temp/10;
i+=2;
break
case TYPE_EXT_DIGITAL: //Digital input
obj.digital=(data[i+1]);
i+=1;
break
case TYPE_EXT_DISTANCE: //Distance sensor input
obj.distance=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_ACC_MOTION: //Acc motion
obj.accMotion=(data[i+1]);
i+=1;
break
case TYPE_IR_TEMP: //IR temperature
var iTemp=(data[i+1]<<8)|(data[i+2]);
iTemp=bin16dec(iTemp);
var eTemp=(data[i+3]<<8)|(data[i+4]);
eTemp=bin16dec(eTemp);
obj.irInternalTemperature=iTemp/10;
obj.irExternalTemperature=eTemp/10;
i+=4;
break
case TYPE_OCCUPANCY: //Body occupancy
obj.occupancy=(data[i+1]);
i+=1;
break
case TYPE_WATERLEAK: //Water leak
obj.waterleak=(data[i+1]);
i+=1;
break
case TYPE_GRIDEYE: //Grideye data
i+=65;
break
case TYPE_PRESSURE: //External Pressure
var temp=(data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4]);
obj.pressure=temp/1000;
i+=4;
break
case TYPE_SOUND: //Sound
obj.soundPeak=data[i+1];
obj.soundAvg=data[i+2];
i+=2;
break
case TYPE_PULSE2: //Pulse 2
obj.pulse2=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_PULSE2_ABS: //Pulse input 2 absolute value
obj.pulseAbs2=(data[i+1]<<24)|(data[i+2]<<16)|(data[i+3]<<8)|(data[i+4]);
i+=4;
break
case TYPE_ANALOG2: //Analog input 2
obj.analog2=(data[i+1]<<8)|(data[i+2]);
i+=2;
break
case TYPE_EXT_TEMP2: //External temp 2
var temp=(data[i+1]<<8)|(data[i+2]);
temp=bin16dec(temp);
obj.externalTemperature2=temp/10;
i+=2;
break
case TYPE_EXT_DIGITAL2: //Digital input 2
obj.digital2=(data[i+1]);
i+=1;
break
default: //somthing is wrong with data
i=data.length;
break
}
}
return obj;
}
function Decoder(bytes, port) {
return DecodeElsysPayload(bytes);
}
function Decode(fPort, bytes) {
return DecodeElsysPayload(bytes);
}
Dekodning af payload i database
CREATE OR REPLACE VIEW loriot.indeklima_dekodet AS
select "eui",
round(hex_to_int(substring("data", 3, 4))/10::decimal,1) as temp,
hex_to_int(substring("data", 9, 2))::int as humidity,
hex_to_int(substring("data", 13, 4))::int as light,
hex_to_int(substring("data", 19, 2))::int as motion,
hex_to_int(substring("data", 23, 4))::int as co2,
round(hex_to_int(substring("data", 29, 4))/1000::decimal,3) as voltage,
timezone('Europe/Berlin'::text, to_timestamp((date_part('epoch'::text,ts) / 1000::double precision)::integer::double precision)) AS ts
from loriot.indeklimasensor
where cmd = 'rx' ;(substring(pl, 23, 4))::decimal