Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCORE-248 Refactor and Test Nodered Plugin for Monorepo #69

Merged
merged 10 commits into from
Oct 18, 2024
37 changes: 37 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
22 changes: 22 additions & 0 deletions plugins/dragino/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "tcore-plugin-dragino",
"version": "0.0.1",
"description": "",
"main": "./src/index.ts",
"type": "module",
"tcore": {
"name": "Dragino",
"short_description": "Adds support for LoRaWAN Dragino sensor encoders",
"full_description": "./README.md",
"icon": "./assets/icon.png",
"types": ["encoder"],
"permissions": ["device-data"]
},
"jest": {
"preset": "ts-jest"
},
"author": "",
"license": "ISC",
"devDependencies": {},
"dependencies": {}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { PayloadEncoderModule } from "@tago-io/tcore-sdk";
import parserLWL01 from "./parser-lwl01";
import parserLHT52 from "./parser-lht52";
import parserLHT65 from "./parser-lht65";
import parserLDS03A from "./parser-lds03a";
import parserLGT92 from "./parser-lgt92";
import parserLDDS75 from "./parser-ldds75";
import parserLSN50V2 from "./parser-lsn50v2d22";
import parserLTC2 from "./parser-ltc2";
import parserLAQ4 from "./parser-laq4";
import parserLWL02 from "./parser-lwl02";
import parserLDS02 from "./parser-lds02";
import parserLSPH01 from "./parser-lsph01";
import parserLSNPK01 from "./parser-lsnpk01";
import parserLAQ4 from "./parser-laq4.ts";
import parserLDDS75 from "./parser-ldds75.ts";
import parserLDS02 from "./parser-lds02.ts";
import parserLDS03A from "./parser-lds03a.ts";
import parserLGT92 from "./parser-lgt92.ts";
import parserLHT52 from "./parser-lht52.ts";
import parserLHT65 from "./parser-lht65.ts";
import parserLSN50V2 from "./parser-lsn50v2d22.ts";
import parserLSNPK01 from "./parser-lsnpk01.ts";
import parserLSPH01 from "./parser-lsph01.ts";
import parserLTC2 from "./parser-ltc2.ts";
import parserLWL01 from "./parser-lwl01.ts";
import parserLWL02 from "./parser-lwl02.ts";

const encoderLWL01 = new PayloadEncoderModule({
id: "network-actility-dragino-lwl01",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { IDeviceDataCreate } from "@tago-io/tcore-sdk/build/Types";
import type { IDeviceDataCreate } from "@tago-io/tcore-sdk/Types";

interface IDeviceDataLatLng extends Omit<IDeviceDataCreate, "location"> {
location?: { lat: number; lng: number };
}
interface IToTagoObject {
[key: string]: string | number | boolean | Partial<IDeviceDataCreate> | undefined;
[key: string]:
| string
| number
| boolean
| Partial<IDeviceDataCreate>
| undefined;
}

const fixVariable = (variable: string) => variable.replace(/ /g, "").toLowerCase();
const fixVariable = (variable: string) =>
variable.replace(/ /g, "").toLowerCase();
/**
* Transforms an object to a TagoIO data array object
*
Expand All @@ -22,12 +28,12 @@ function toTagoFormat(objectItem: IToTagoObject, group?: string, prefix = "") {
const item = objectItem[key];
if (typeof item === "object") {
result.push({
variable: fixVariable(item["variable"] || `${prefix}${key}`),
value: item["value"],
group: item["group"] || group,
metadata: item["metadata"],
location: item["location"],
unit: item["unit"],
variable: fixVariable(item.variable || `${prefix}${key}`),
value: item.value,
group: item.group || group,
metadata: item.metadata,
location: item.location,
unit: item.unit,
});
} else {
result.push({
Expand All @@ -41,4 +47,4 @@ function toTagoFormat(objectItem: IToTagoObject, group?: string, prefix = "") {
return result;
}

export { IToTagoObject, toTagoFormat, IDeviceDataLatLng };
export { type IToTagoObject, toTagoFormat, type IDeviceDataLatLng };
180 changes: 180 additions & 0 deletions plugins/dragino/src/parser-laq4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import type { IDeviceDataCreate } from "@tago-io/tcore-sdk/Types";

/**
* @param bytes
* @returns
*/
function Decoder(bytes: Buffer) {
if (bytes.length === 11) {
const data = [];
// Battery
data.push({
variable: "Bat_V",
value: ((bytes[0] << 8) | bytes[1]) / 1000,
unit: "V",
}); //0dac -> 3500/1000 -> 3.5
// Mode (alarm flag)
const mode = (bytes[2] & 0x7c) >> 2; //04 --> 1 | 7c --> 31
if (mode === 1) {
data.push({ variable: "Work_mode", value: "CO2" });
data.push({
variable: "Alarm_status",
value: bytes[2] & 0x01 ? "TRUE" : "FALSE",
}); // 04 -> FALSE
// TVOC
data.push({
variable: "TVOC_ppb",
value: (bytes[3] << 8) | bytes[4],
unit: "ppb",
}); //00fa -> 250
// CO2
data.push({
variable: "CO2_ppm",
value: (bytes[5] << 8) | bytes[6],
unit: "ppm",
}); //00fa -> 250
// Temperature
data.push({
variable: "TempC_SHT",
value: Number.parseFloat(
((((bytes[7] << 24) >> 16) | bytes[8]) / 10).toFixed(2),
),
unit: "°C",
}); //ff = -256 ef = 239 --> -17 / 10 = -1.7
// Humidity
data.push({
variable: "Hum_SHT",
value: Number.parseFloat(
(((bytes[9] << 8) | bytes[10]) / 10).toFixed(1),
),
unit: "%",
}); //03bb => 955/10 => 95.5
} else if (mode === 31) {
data.push({ variable: "Work_mode", value: "ALARM" });
// Temp minimum of alarm value
data.push({
variable: "SHTTEMPMIN",
value: (bytes[3] << 24) >> 24,
unit: "°C",
});
// Temp maximum of alarm value
data.push({
variable: "SHTTEMPMAX",
value: (bytes[4] << 24) >> 24,
unit: "°C",
});
// Hum minumum of alarm value
data.push({ variable: "SHTHUMMIN", value: bytes[5], unit: "%" });
// Hum maximum of alarm value
data.push({ variable: "SHTHUMMAX", value: bytes[6], unit: "%" });
// CO2 minimum of alarm value
data.push({
variable: "CO2MIN",
value: (bytes[7] << 8) | bytes[8],
unit: "ppm",
});
// CO2 maximum of alarm value
data.push({
variable: "CO2MAX",
value: (bytes[9] << 8) | bytes[10],
unit: "ppm",
});
}
return data;
}
if (bytes.length % 11 === 0) {
const data = [];
for (let i = 0; i < bytes.length; ) {
//CO2
data.push({
variable: `entry_${i / 11}_CO2`,
value: (bytes[i + 1] << 8) | bytes[i + 0],
unit: "ppm",
});
//Poll message flag & ext
data.push({
variable: `entry_${i / 11}_Poll_message_flag`,
value: bytes[i + 2] >> 7,
});
data.push({
variable: `entry_${i / 11}_Mode`,
value: (bytes[i + 2] & 0x7c) >> 2,
});
data.push({
variable: `entry_${i / 11}_Alarm`,
value: bytes[i + 2] & 0x01 ? "TRUE" : "FALSE",
});
//Temperature
data.push({
variable: `entry_${i / 11}_Temp`,
value: Number.parseFloat(
((((bytes[i + 3] << 24) >> 16) | bytes[i + 4]) / 100).toFixed(2),
),
unit: "°C",
});
//Humidity
data.push({
variable: `entry_${i / 11}_Hum`,
value: Number.parseFloat(
(((bytes[i + 5] << 8) | bytes[i + 6]) / 10).toFixed(2),
),
unit: "%",
});
//Unix Time Stamp
data.push({
variable: `entry_${i / 11}_unix_time`,
value:
((bytes[i + 7] << 24) |
(bytes[i + 8] << 16) |
(bytes[i + 9] << 8) |
bytes[i + 10]) *
1000,
});
i += 11;
}
return data;
}
return [
{
variable: "parser_error",
value:
"Parser Error: payload length does not match, must have 11 bytes or it's multiples.",
},
];
}

/**
* Decode data from Dragino sensor
*
* @param payload - any payload sent by the device
* @returns {IDeviceDataCreate[]} data to be stored
*/
export default async function parserLAQ4(
payload: IDeviceDataCreate[],
): Promise<IDeviceDataCreate[]> {
if (!Array.isArray(payload)) {
payload = [payload];
}

const data = payload.find(
(x) =>
x.variable === "payload" ||
x.variable === "payload_raw" ||
x.variable === "data",
);
if (data) {
const serie = data.serie || new Date().getTime();
const bytes = Buffer.from(String(data.value), "hex");

payload = payload.concat(Decoder(bytes)).map((x) => ({
variable: x.variable.toLowerCase(),
value: x.value,
unit: x.unit,
serie,
}));
}

return payload;
}

// console.log(payload);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IDeviceDataCreate } from "@tago-io/tcore-sdk/build/Types";
import { toTagoFormat } from "./lib/to-tago-format";
import type { IDeviceDataCreate } from "@tago-io/tcore-sdk/Types";
import { toTagoFormat } from "./lib/to-tago-format.ts";

/**
* @param bytes
Expand Down Expand Up @@ -28,13 +28,18 @@ function Decoder(bytes: Buffer) {
* @param payload - any payload sent by the device
* @returns {IDeviceDataCreate[]} data to be stored
*/
export default async function parserLDDS75(payload: IDeviceDataCreate[]): Promise<IDeviceDataCreate[]> {
export default async function parserLDDS75(
payload: IDeviceDataCreate[],
): Promise<IDeviceDataCreate[]> {
if (!Array.isArray(payload)) {
payload = [payload];
}

const payloadRaw = payload.find(
(x) => x.variable === "payload" || x.variable === "payload_raw" || x.variable === "data"
(x) =>
x.variable === "payload" ||
x.variable === "payload_raw" ||
x.variable === "data",
);
if (payloadRaw) {
// Get a unique serie for the incoming data.
Expand All @@ -47,7 +52,10 @@ export default async function parserLDDS75(payload: IDeviceDataCreate[]): Promis
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
// Catch any error in the parse code and send to parse_error variable.
varsToTago = varsToTago.concat({ variable: "parse_error", value: e.message || e });
varsToTago = varsToTago.concat({
variable: "parse_error",
value: e.message || e,
});
}

payload = payload.concat(varsToTago);
Expand Down
Loading
Loading