Skip to content
10 changes: 10 additions & 0 deletions vendor/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,16 @@ vendors:
name: Parametric Engineering GmbH
vendorID: 315

- id: pmx
name: PMX Systems AG
vendorID: 1141
website: https://www.pmx.systems
logo: pmx-logo.svg
description: PMX Systems AG is a Swiss company specialising in smart outdoor sensors.
social:
linkedin: https://www.linkedin.com/company/pmx-systems
github: pmx-systems

- id: proesys
name: ProEsys SRL
vendorID: 323
Expand Down
2 changes: 2 additions & 0 deletions vendor/pmx/index.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
endDevices:
- pmx-tcr
26 changes: 26 additions & 0 deletions vendor/pmx/pmx-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions vendor/pmx/pmx-tcr-codec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# 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: pmx-tcr.js
examples:
- description: device id uplink
input:
fPort: 190
bytes: [210, 10, 2, 2, 17, 0, 66, 0]
output:
data:
typestr: TCR-DLI
fu_level: PRO
speedclass: HS
fw_version: 1.1.0
sbx_version: 4.2.0

- description: Unfiltered detections counter (UDC) uplink (port 13)
input:
fPort: 13
bytes: [162, 20, 10, 3, 232, 50, 4, 76, 52, 51]
output:
data:
time: 2010
udc_ltr_cnt: 1000
udc_ltr_spd: 50
udc_rtl_cnt: 1100
udc_rtl_spd: 52
volts: 5.1

- description: cat 1 counter uplink (port 14)
input:
fPort: 14
bytes: [162, 20, 10, 3, 232, 50, 4, 76, 52, 51]
output:
data:
time: 2010
cat1_ltr_cnt: 1000
cat1_ltr_spd: 50
cat1_rtl_cnt: 1100
cat1_rtl_spd: 52
volts: 5.1

- description: cat 2 counter uplink (port 15)
input:
fPort: 15
bytes: [162, 20, 10, 3, 232, 50, 4, 76, 52, 51]
output:
data:
time: 2010
cat2_ltr_cnt: 1000
cat2_ltr_spd: 50
cat2_rtl_cnt: 1100
cat2_rtl_spd: 52
volts: 5.1

- description: cat 3 counter uplink (port 16)
input:
fPort: 16
bytes: [162, 20, 10, 3, 232, 50, 4, 76, 52, 51]
output:
data:
time: 2010
cat3_ltr_cnt: 1000
cat3_ltr_spd: 50
cat3_rtl_cnt: 1100
cat3_rtl_spd: 52
volts: 5.1

- description: cat 4 counter uplink (port 17)
input:
fPort: 17
bytes: [162, 20, 10, 3, 232, 50, 4, 76, 52, 51]
output:
data:
time: 2010
cat4_ltr_cnt: 1000
cat4_ltr_spd: 50
cat4_rtl_cnt: 1100
cat4_rtl_spd: 52
volts: 5.1
Binary file added vendor/pmx/pmx-tcr-kit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
223 changes: 223 additions & 0 deletions vendor/pmx/pmx-tcr.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/**
* PMX TCR Payload
*
* THIS SOFTWARE IS PROVIDED BY PMX SYSTEMS AG AND ITS CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
const DeviceTypes = [
"TCR-LS", /* 0 Low Speed (2 Speed Groups) */
"TCR-LSS", /* 1 Low Speed Solar (2 Speed Groups) */
"TCR-HS", /* 2 High Speed (4 Speed Groups) */
"TCR-HSS", /* 3 High Speed Solar (4 Speed Groups) */
"TCR-LSA", /* 4 Low Speed AC Powered (2 Speed Groups) */
"TCR-LSB", /* 5 Low Speed AC External Battery Powered (4 Speed Groups) */
"TCR-HSA", /* 6 High Speed AC Powered (4 Speed Groups) */
"TCR-HSB", /* 7 High Speed External Battery Powered (4 Speed Groups) */
"TCR-LSBS", /* 8 Low Speed External Battery (External) + Solar (2 Speed Groups) */
"TCR-HSBS", /* 9 High Speed External Battery (External) + Solar (4 Speed Groups) */
"TCR-DLI", /* 10 DC powered, LoRaWAN, Internal Antenna */
"TCR-DLE", /* 11 DC powered, LoRaWAN, External Antenna */
"TCR-SLI", /* 12 Solar powered, LoRaWAN, Internal Antenna */
"TCR-SLE", /* 13 Solar powered, LoRaWAN, External Antenna */
"PCR2-OD", /* 14 Outdoor Models w/o battery*/
"PCR2-ODS", /* 15 Outdoor Models, Solar Powered */
];

// Function levels
const FeatureLevel = [
"BASIC", /* 0 BASIC Features enabled (no licence installed) */
"ADVANCED", /* 1 ADVANCED Features enabled */
"PRO" /* 2 PRO Features enabled */
];

// Speed classes
const SpeedClassTypes = [
"P", /* 0 Speed class for people counting (very low speed) */
"LS", /* 1 Low speed traffic counting */
"HS" /* 2 High speed traffic counting */
];

// Array of all available config keys (since JavaScript has no enum)
// Use this array to have a key instead of just an index number
const ConfigKeys = {

// 0 Totals
LR_CF_CMD_CAT0_ENABLED: 0x01, /** Enable category */
LR_CF_CMD_CAT0_MIN_SIZE: 0x02, /** Change min object size of category */
LR_CF_CMD_CAT0_MAX_SIZE: 0x03, /** Overwrite max object size of category */
LR_CF_CMD_CAT0_MIN_SPEED: 0x04, /** Overwrite min object speed of category */
LR_CF_CMD_CAT0_MAX_SPEED: 0x05, /** Overwrite max object speed of category */

// 1
LR_CF_CMD_CAT1_ENABLED: 0x11, /** Enable category */
LR_CF_CMD_CAT1_MIN_SIZE: 0x12, /** Overwrite min object size of category */
LR_CF_CMD_CAT1_MAX_SIZE: 0x13, /** Overwrite max object size of category */
LR_CF_CMD_CAT1_MIN_SPEED: 0x14, /** Overwrite min object speed of category */
LR_CF_CMD_CAT1_MAX_SPEED: 0x15, /** Overwrite max object speed of category */

// 2
LR_CF_CMD_CAT2_ENABLED: 0x21, /** Enable category */
LR_CF_CMD_CAT2_MIN_SIZE: 0x22, /** Overwrite min object size of category */
LR_CF_CMD_CAT2_MAX_SIZE: 0x23, /** Overwrite max object size of category */
LR_CF_CMD_CAT2_MIN_SPEED: 0x24, /** Overwrite min object speed of category */
LR_CF_CMD_CAT2_MAX_SPEED: 0x25, /** Overwrite max object speed of category */

// 3
LR_CF_CMD_CAT3_ENABLED: 0x31, /** Enable category */
LR_CF_CMD_CAT3_MIN_SIZE: 0x32, /** Overwrite min object size of category */
LR_CF_CMD_CAT3_MAX_SIZE: 0x33, /** Overwrite max object size of category */
LR_CF_CMD_CAT3_MIN_SPEED: 0x34, /** Overwrite min object speed of category */
LR_CF_CMD_CAT3_MAX_SPEED: 0x35, /** Overwrite max object speed of category */

// 4
LR_CF_CMD_CAT4_ENABLED: 0x41, /** Enable category */
LR_CF_CMD_CAT4_MIN_SIZE: 0x42, /** Overwrite min object size of category */
LR_CF_CMD_CAT4_MAX_SIZE: 0x43, /** Overwrite max object size of category */
LR_CF_CMD_CAT4_MIN_SPEED: 0x44, /** Overwrite min object speed of category */
LR_CF_CMD_CAT4_MAX_SPEED: 0x45, /** Overwrite max object speed of category */

/* Device Settings */
LR_CF_CMD_LIC_KEY: 0x51, /** Licence Key RW */
LR_CF_CMD_FU_LEVEL: 0x52, /** Feauture Level RO*/
LR_CF_CMD_SPEED_CLASS: 0x53, /** Feauture Level RO*/
LR_CF_CMD_MEAS_INTERVAL: 0x54, /** Meas Interval RW */

/* Radar Settings */
LR_CF_CMD_RADAR_ENABLED: 0x61, /** Switch radar module on / off */
LR_CF_CMD_RADAR_CHANNEL: 0x62, /** Choose Radar Channel: 1, 2 */
LR_CF_CMD_RADAR_SENS: 0x63, /** Radar Sensitivity Level [%]*/
LR_CF_CMD_RADAR_AUTOSENS: 0x64, /** Enable Autosens, 0 = off , 1 = on */

/* LoRaWAN Settings */
LR_CF_CMD_LORA_UL_CONFIRMED: 0x71, /** Set confirmed uplinks mode*/


LR_CF_CMD_CLEAR: 0xcc, /** cf starts the configuration uplink sequence */
LR_CF_CMD_CONFIG_SEQ: 0xcf, /** cf starts the configuration uplink sequence */
LR_CF_CMD_DEFAULTS: 0xdf, /** df set factory defaults (use ee for saving to ROM) */
LR_CF_CMD_RESTART: 0xee /** ee Restart device with new settings */
};

function d2_decoder(bytes, port) {
var obj = {};
obj.typestr = DeviceTypes[bytes[1]]; // 00: TCR-LS, 01: TCR-LSS , ...
obj.fu_level = FeatureLevel[bytes[2]]; // 00: BASIC, 01: ADVANCED , ...
obj.speedclass = SpeedClassTypes[bytes[3]]; // 00: Speedclass, 01: LS , 02: HS
obj.fw_version = (bytes[4] & 0xf0) / 0x10 + "." + (bytes[4] & 0x0f) + "." + bytes[5]; // Firmware Major Version
obj.sbx_version = (bytes[6] & 0xf0) / 0x10 + "." + (bytes[6] & 0x0f) + "." + bytes[7]; // SBX Solar Charger Firmware Version
return obj;
}

function a2_decoder(bytes, port) {
var obj = {};

if (port == 13) // Unfiltered Detections
{
obj.time = bytes[1] * 100 + bytes[2]; // Measure Interval End Timestamp (Military Time format)
obj.udc_ltr_cnt = (bytes[3] << 8) | (bytes[4]); // Left-to-Right (LTR) Counter Value (0-65535)
obj.udc_ltr_spd = bytes[5]; // Left-to-Right (LTR) average speed of all objects counted in this interval [km/h]
obj.udc_rtl_cnt = (bytes[6] << 8) | (bytes[7]); // Right-to-Left (RTL) Counter Value (0-65535)
obj.udc_rtl_spd = bytes[8]; // Right-to-Left (RTL) average speed of all objects counted in this interval [km/h]
}

if (port == 14) // Filter Category 1
{
obj.time = bytes[1] * 100 + bytes[2]; // Measure Interval End Timestamp (Military Time format)
obj.cat1_ltr_cnt = (bytes[3] << 8) | (bytes[4]); // Left-to-Right (LTR) Counter Value (0-65535)
obj.cat1_ltr_spd = bytes[5]; // Left-to-Right (LTR) average speed of all objects counted in this interval [km/h]
obj.cat1_rtl_cnt = (bytes[6] << 8) | (bytes[7]); // Right-to-Left (RTL) Counter Value (0-65535)
obj.cat1_rtl_spd = bytes[8]; // Right-to-Left (RTL) average speed of all objects counted in this interval [km/h]
}

if (port == 15) // Filter Category 2
{
obj.time = bytes[1] * 100 + bytes[2]; // Measure Interval End Timestamp (Military Time format)
obj.cat2_ltr_cnt = (bytes[3] << 8) | (bytes[4]); // Left-to-Right (LTR) Counter Value (0-65535)
obj.cat2_ltr_spd = bytes[5]; // Left-to-Right (LTR) average speed of all objects counted in this interval [km/h]
obj.cat2_rtl_cnt = (bytes[6] << 8) | (bytes[7]); // Right-to-Left (RTL) Counter Value (0-65535)
obj.cat2_rtl_spd = bytes[8]; // Right-to-Left (RTL) average speed of all objects counted in this interval [km/h]
}

if (port == 16) // Filter Category 3
{
obj.time = bytes[1] * 100 + bytes[2]; // Measure Interval End Timestamp (Military Time format)
obj.cat3_ltr_cnt = (bytes[3] << 8) | (bytes[4]); // Left-to-Right (LTR) Counter Value (0-65535)
obj.cat3_ltr_spd = bytes[5]; // Left-to-Right (LTR) average speed of all objects counted in this interval [km/h]
obj.cat3_rtl_cnt = (bytes[6] << 8) | (bytes[7]); // Right-to-Left (RTL) Counter Value (0-65535)
obj.cat3_rtl_spd = bytes[8]; // Right-to-Left (RTL) average speed of all objects counted in this interval [km/h]
}

if (port == 17) // Filter Category 4
{
obj.time = bytes[1] * 100 + bytes[2]; // Measure Interval End Timestamp (Military Time format)
obj.cat4_ltr_cnt = (bytes[3] << 8) | (bytes[4]); // Left-to-Right (LTR) Counter Value (0-65535)
obj.cat4_ltr_spd = bytes[5]; // Left-to-Right (LTR) average speed of all objects counted in this interval [km/h]
obj.cat4_rtl_cnt = (bytes[6] << 8) | (bytes[7]); // Right-to-Left (RTL) Counter Value (0-65535)
obj.cat4_rtl_spd = bytes[8]; // Right-to-Left (RTL) average speed of all objects counted in this interval [km/h]
}

obj.volts = bytes[9] / 10; // Power supply voltage. Divide by 10 to get volts.
return obj;
}

function c2_decoder(bytes, port) {
var obj = {};

// 8 Bit values
if (bytes.length == 3) {
obj[ConfigKeys[bytes[1]]] = bytes[2];
}

// 16 Bit values
if (bytes.length >= 4) {
obj[ConfigKeys[bytes[1]]] = (bytes[2] << 8) | (bytes[3]);
}
return obj;
}

function bin16dec(bin) {
var num = bin & 0xFFFF;
if (0x8000 & num) num = -(0x010000 - num);
return num;
}

function hexToBytes(hex) {
hex = hex.replace(/\s/g, "");
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}


function decodeUplink(input) {
var data = {};
var bytes = input.bytes;
var port = input.fPort;

// it's a Device ID Payload V2 (PMX Firmware for TCR)
if (port == 190 && bytes[0] == 0xd2) {

data = d2_decoder(bytes, port);
}

// it's a Counter Payload V2 (PMX Firmware for TCR)
if (port >= 13 && port <= 17 && bytes[0] == 0xa2) {

data = a2_decoder(bytes, port);
}

// it's a Config Payload Response (PMX Firmware for TCR)
if (port == 1 && bytes[0] == 0xc2) {

data = c2_decoder(bytes, port);
}
return {
data: data,
};
}
Binary file added vendor/pmx/pmx-tcr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading