Skip to content

Commit

Permalink
Merge pull request #36 from tago-io/feat/connector-elsys
Browse files Browse the repository at this point in the history
feat/connector-elsys
  • Loading branch information
FabianoEger authored Jul 12, 2024
2 parents 8cca193 + 271f481 commit 657f5e3
Show file tree
Hide file tree
Showing 66 changed files with 3,175 additions and 0 deletions.
Binary file added decoders/connector/elsys/elt-2/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions decoders/connector/elsys/elt-2/connector.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "../../../../schema/connector.json",
"name": "ELSYS ELT-2",
"images": {
"logo": "./assets/logo.png"
},
"versions": {
"v1.0.0": {
"src": "./v1.0.0/payload.js",
"manifest": "./v1.0.0/payload-config.jsonc"
}
}
}
1 change: 1 addition & 0 deletions decoders/connector/elsys/elt-2/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ELT-2 measures analog or digital signals and can handle up to two external sensors simultaneously over LoRAWAN®
23 changes: 23 additions & 0 deletions decoders/connector/elsys/elt-2/v1.0.0/payload-config.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "../../../../../schema/connector_details.json",
"description": "../description.md",
"install_text": "ELT-2 from ELSYS.se is the ideal sensor for measuring in advanced places or in extreme weather conditions. \n\nIt is easy to install and configure to form your solution. ELT-2 has two generic inputs. \n\nYou can configure ELT-2 for external temperature probe, pulse counting, analog-input 0-10V, digital-input, water leak, switch, distance sensor, soil moister sensor and many more options. \n\nELT-2 can be equipt with add on modules to get extra features like external PT1000 sensors, load cell input, or output control. ",
"install_end_text": "",
"device_annotation": "",
"device_parameters": [],
"networks": [
"../../../../network/lorawan-kerlink/v1.0.0/payload.js",
"../../../../network/lorawan-loriot/v1.0.0/payload.js",
"../../../../network/lorawan-citykinect/v1.0.0/payload.js",
"../../../../network/lorawan-everynet/v1.0.0/payload.js",
"../../../../network/lorawan-machineq/v1.0.0/payload.js",
"../../../../network/lorawan-orbiwise/v1.0.0/payload.js",
"../../../../network/lorawan-tektelic/v1.0.0/payload.js",
"../../../../network/lorawan-actility/v1.0.0/payload.js",
"../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js",
"../../../../network/lorawan-swisscom/v1.0.0/payload.js",
"../../../../network/lorawan-chirpstack/v1.0.0/payload.js",
"../../../../network/lorawan-helium/v1.0.0/payload.js",
"../../../../network/lorawan-brdot/v1.0.0/payload.js"
]
}
230 changes: 230 additions & 0 deletions decoders/connector/elsys/elt-2/v1.0.0/payload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
const TYPE_TEMP = 0x01; // temp 2 bytes -3276.8°C -->3276.7°C
const TYPE_RH = 0x02; // Humidity 1 byte 0-100%
const TYPE_ACC = 0x03; // acceleration 3 bytes X,Y,Z -128 --> 127 +/-63=1G
const TYPE_LIGHT = 0x04; // Light 2 bytes 0-->65535 Lux
const TYPE_MOTION = 0x05; // No of motion 1 byte 0-255
const TYPE_CO2 = 0x06; // Co2 2 bytes 0-65535 ppm
const TYPE_VDD = 0x07; // VDD 2byte 0-65535mV
const TYPE_ANALOG1 = 0x08; // VDD 2byte 0-65535mV
const TYPE_GPS = 0x09; // 3bytes lat 3bytes long binary
const TYPE_PULSE1 = 0x0A; // 2bytes relative pulse count
const TYPE_PULSE1_ABS = 0x0B; // 4bytes no 0->0xFFFFFFFF
const TYPE_EXT_TEMP1 = 0x0C; // 2bytes -3276.5C-->3276.5C
const TYPE_EXT_DIGITAL = 0x0D; // 1bytes value 1 or 0
const TYPE_EXT_DISTANCE = 0x0E; // 2bytes distance in mm
const TYPE_ACC_MOTION = 0x0F; // 1byte number of vibration/motion
const TYPE_IR_TEMP = 0x10; // 2bytes internal temp 2bytes external temp -3276.5C-->3276.5C
const TYPE_OCCUPANCY = 0x11; // 1byte data
const TYPE_WATERLEAK = 0x12; // 1byte data 0-255
const TYPE_GRIDEYE = 0x13; // 65byte temperature data 1byte ref+64byte external temp
const TYPE_PRESSURE = 0x14; // 4byte pressure data (hPa)
const TYPE_SOUND = 0x15; // 2byte sound data (peak/avg)
const TYPE_PULSE2 = 0x16; // 2bytes 0-->0xFFFF
const TYPE_PULSE2_ABS = 0x17; // 4bytes no 0->0xFFFFFFFF
const TYPE_ANALOG2 = 0x18; // 2bytes voltage in mV
const TYPE_EXT_TEMP2 = 0x19; // 2bytes -3276.5C-->3276.5C
const TYPE_EXT_DIGITAL2 = 0x1A; // 1bytes value 1 or 0
const TYPE_EXT_ANALOG_UV = 0x1B; // 4 bytes signed int (uV)
const TYPE_DEBUG = 0x3D; // 4bytes debug

function toTagoFormat(object_item, group, prefix = '', location_var) {
const result = [];
for (const key in object_item) {
// if (ignore_vars.includes(key)) continue;

if (typeof object_item[key] === 'object') {
result.push({
variable: object_item[key].variable || `${prefix}${key}`,
value: object_item[key].value,
group: object_item[key].group || group,
metadata: object_item[key].metadata,
location: object_item[key].location || location_var,
unit: object_item[key].unit,
});
} else {
result.push({
variable: `${prefix}${key}`,
value: object_item[key],
location: location_var,
group,
});
}
}

return result;
}

function bin16dec(bin) {
let num = bin & 0xFFFF;
if (0x8000 & num) num = -(0x010000 - num);
return num;
}
function bin8dec(bin) {
let 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) {
const 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 = { value: temp / 10, unit: '°C' };
i += 2;
break;
case TYPE_RH: // Humidity
var rh = (data[i + 1]);
obj.humidity = { value: rh, unit: '%' };
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 = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'Lux' };
i += 2;
break;
case TYPE_MOTION: // Motion sensor(PIR)
obj.motion = (data[i + 1]);
i += 1;
break;
case TYPE_CO2: // CO2
obj.co2 = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'ppm' };
i += 2;
break;
case TYPE_VDD: // Battery level
obj.vdd = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'mV' };
i += 2;
break;
case TYPE_ANALOG1: // Analog input 1
obj.analog1 = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'mV' };
i += 2;
break;
case TYPE_GPS: // gps
const lat = (data[i + 1] << 16) | (data[i + 2] << 8) | (data[i + 3]);
const lng = (data[i + 4] << 16) | (data[i + 5] << 8) | (data[i + 6]);
obj.location = { value: `${lat},${lng}`, location: { lat, lng } };
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 = { value: temp / 10, unit: '°C' };
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 = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'mm' };
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 = { value: iTemp / 10, unit: '°C' };
obj.irExternalTemperature = { value: eTemp / 10, unit: '°C' };
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
var ref = data[i + 1];
i++;
obj.grideye = [];
for (let j = 0; j < 64; j++) {
obj.grideye[j] = ref + (data[1 + i + j] / 10.0);
}
i += 64;
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 = { value: temp / 1000, unit: 'hPa' };
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 = { value: (data[i + 1] << 8) | (data[i + 2]), unit: 'mV' };
i += 2;
break;
case TYPE_EXT_TEMP2: // External temp 2
var temp = (data[i + 1] << 8) | (data[i + 2]);
temp = bin16dec(temp);
obj.externalTemperature2 = { value: temp / 10, unit: '°C' };
i += 2;
break;
case TYPE_EXT_DIGITAL2: // Digital input 2
obj.digital2 = (data[i + 1]);
i += 1;
break;
case TYPE_EXT_ANALOG_UV: // Load cell analog uV
obj.analogUv = { value: (data[i + 1] << 24) | (data[i + 2] << 16) | (data[i + 3] << 8) | (data[i + 4]), unit: 'uV' };
i += 4;
break;
default: // somthing is wrong with data
i = data.length;
break;
}
}
return obj;
}

function Decoder(bytes, port) {
return DecodeElsysPayload(bytes);
}


// payload = [{ variable: 'payload', value: '0100e202290400270506060308070d62', group: '122a' }];

const data = payload.find(x => x.variable === 'data' || x.variable === 'payload');
if (data) {
const group = data.group || new Date().getTime();
const vars_to_tago = Decoder(Buffer.from(data.value, 'hex'));

payload = [...payload, ...toTagoFormat(vars_to_tago, group, '', vars_to_tago.location)];
// payload = payload.filter(x => !ignore_vars.includes(x.variable));
}
17 changes: 17 additions & 0 deletions decoders/connector/elsys/elt-2/v1.0.0/payload.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, test, expect } from "vitest";

import { decoderRun } from "../../../../../src/functions/decoder-run";

const file_path = "decoders/connector/elsys/elt-2/v1.0.0/payload.js" as const;

describe("Shall not be parsed", () => {
let payload = [{ variable: "shallnotpass", value: "04096113950292" }];
payload = decoderRun(file_path, { payload });
test("Output Result", () => {
expect(Array.isArray(payload)).toBe(true);
});

test("Not parsed Result", () => {
expect(payload).toEqual([{ variable: "shallnotpass", value: "04096113950292" }]);
});
});
Binary file added decoders/connector/elsys/elt-lite/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions decoders/connector/elsys/elt-lite/connector.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "../../../../schema/connector.json",
"name": "ELSYS ELT Lite",
"images": {
"logo": "./assets/logo.png"
},
"versions": {
"v1.0.0": {
"src": "./v1.0.0/payload.js",
"manifest": "./v1.0.0/payload-config.jsonc"
}
}
}
1 change: 1 addition & 0 deletions decoders/connector/elsys/elt-lite/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ELT is an easy but powerful LoRAWAN® device for measuring analog or digital signals
23 changes: 23 additions & 0 deletions decoders/connector/elsys/elt-lite/v1.0.0/payload-config.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "../../../../../schema/connector_details.json",
"description": "../description.md",
"install_text": "ELT Lite from ELSYS.se is the ideal device to use together with an external sensor. \n\nUse it together with an electricity meter, flow meter, analog sensor, moisture sensor or something else that fits your needs. \n\nELT Lite has one generic input. You can configure ELT Lite for external temperature probe, pulse counting, analog-input 0-10V, digital-input, water leak, switch, and many more options. ",
"install_end_text": "",
"device_annotation": "",
"device_parameters": [],
"networks": [
"../../../../network/lorawan-kerlink/v1.0.0/payload.js",
"../../../../network/lorawan-loriot/v1.0.0/payload.js",
"../../../../network/lorawan-citykinect/v1.0.0/payload.js",
"../../../../network/lorawan-everynet/v1.0.0/payload.js",
"../../../../network/lorawan-machineq/v1.0.0/payload.js",
"../../../../network/lorawan-orbiwise/v1.0.0/payload.js",
"../../../../network/lorawan-tektelic/v1.0.0/payload.js",
"../../../../network/lorawan-actility/v1.0.0/payload.js",
"../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js",
"../../../../network/lorawan-swisscom/v1.0.0/payload.js",
"../../../../network/lorawan-chirpstack/v1.0.0/payload.js",
"../../../../network/lorawan-helium/v1.0.0/payload.js",
"../../../../network/lorawan-brdot/v1.0.0/payload.js"
]
}
Loading

0 comments on commit 657f5e3

Please sign in to comment.