Skip to content

Commit

Permalink
Merge branch 'main' into sensoterra
Browse files Browse the repository at this point in the history
  • Loading branch information
J2thatsme authored Jan 10, 2025
2 parents 4f60b19 + 690873c commit 854dd2c
Show file tree
Hide file tree
Showing 135 changed files with 5,546 additions and 274 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.

---

# [1.57.2] - 2025-01-09

### Changed

- Added downlink encoder for the MCLimate Vicki

# [1.57.1] - 2024-12-12

### Changed

- Implemented warm desk logic. Occupancy devices now output an additional time how long they where unoccupied
- Standardised the occupancy value and added minutesSinceLastOccupied for the upcoming warmdesk logic

# [1.57.0] - 2024-11-28

### Added
Expand Down
2 changes: 1 addition & 1 deletion data-models/environment/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,4 @@
}
}
}
}
}
19 changes: 18 additions & 1 deletion data-models/spaces/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@
"type": "boolean"
}
},
"occupancy": {
"integer": {
"title": "Occupancy",
"description": "Space occupancy. 0 = Unoccupied / 1 = Occupied but movement detected / 2 = Occupied.",
"type": "integer",
"minimum": 0,
"maximum": 2
}
},
"minutesSinceLastOccupied": {
"minutes": {
"title": "Minutes since last occupied",
"description": "Minutes since last occupied value was registered",
"type": "integer",
"unit": "m"
}
},
"motion": {
"count": {
"measurementType": "akenza/spaces/motion/count",
Expand Down Expand Up @@ -53,4 +70,4 @@
}
}
}
}
}
20 changes: 10 additions & 10 deletions lib/test/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const fs = require("fs");
const chai = require("chai");
const request = require("sync-request");
var Validator = require("jsonschema").Validator;
const { Validator } = require("jsonschema");

try {
require("dotenv").config();
Expand Down Expand Up @@ -65,7 +65,7 @@ exports.init = (script) => {
const scriptPath = getCallerFile().replace(".spec", "");
const src = fs.readFileSync(scriptPath, "utf8");
const payload = {
event: event,
event,
script: src,
};
const res = request("POST", process.env.SCRIPT_RUN_URL, {
Expand All @@ -78,10 +78,10 @@ exports.init = (script) => {
nExpectation += 1;
});

return results; //TODO
} else {
return consume(event);
return results; // TODO
}
return consume(event);


assert.equal(
nExpectation,
Expand All @@ -95,7 +95,7 @@ const schemaCache = {};

function getMeasurementType(schema, path) {
let measurementType = schema;
var arr = path.split(".").filter((key) => key !== "");
const arr = path.split(".").filter((key) => key !== "");
while (arr.length) {
const key = arr.shift();
if (measurementType[key] !== undefined) {
Expand Down Expand Up @@ -127,13 +127,13 @@ function loadRemoteSchema(uri) {

// Validates the schema and checks for missing schema keys
exports.validateSchema = (data, schema, throwError) => {
var v = new Validator();
const v = new Validator();
v.addSchema(schema);

var nextSchema = v.unresolvedRefs.shift();
let nextSchema = v.unresolvedRefs.shift();
while (nextSchema !== undefined) {
const schema = loadRemoteSchema(nextSchema);
schema["$id"] = nextSchema;
schema.$id = nextSchema;
v.addSchema(schema, nextSchema);
nextSchema = v.unresolvedRefs.shift();
}
Expand Down Expand Up @@ -174,7 +174,7 @@ function getCallerFile() {
break;
}
}
} catch (err) {}
} catch (err) { }
Error.prepareStackTrace = _pst;

return filename;
Expand Down
13 changes: 11 additions & 2 deletions types/ascoel/PB868LR/default.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@
"type": "boolean",
"description": "True if the button was pushed"
},
"buttonPushedNumeric": {
"title": "Button pushed numeric",
"type": "integer",
"description": "Button pushed represented as an integer"
},
"count": {
"title": "Count",
"type": "integer",
"description": "Count of button presses"
}
},
"required": ["buttonPushed", "count"]
}
"required": [
"buttonPushed",
"buttonPushedNumeric",
"count"
]
}
1 change: 1 addition & 0 deletions types/ascoel/PB868LR/uplink.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function consume(event) {
break;
case 40:
data.buttonPushed = !!Bits.bitsToUnsigned(bits.substr(7, 1));
data.buttonPushedNumeric = Number(data.buttonPushed);
data.count = Bits.bitsToUnsigned(bits.substr(8, 16));
break;
default:
Expand Down
1 change: 1 addition & 0 deletions types/ascoel/PB868LR/uplink.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ describe("Ascoel Push button Uplink", () => {

assert.equal(value.topic, "default");
assert.equal(value.data.buttonPushed, true);
assert.equal(value.data.buttonPushedNumeric, 1);
assert.equal(value.data.count, 1);

utils.validateSchema(value.data, defaultSchema, { throwError: true });
Expand Down
20 changes: 10 additions & 10 deletions types/bosch/parkingLotSensor/occupancy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
"title": "Occupancy",
"properties": {
"occupancy": {
"title": "Occupancy",
"description": "Space occupancy. 0 = Unoccupied / 1 = Occupied.",
"type": "integer",
"minimum": 0,
"maximum": 1
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/occupancy/integer"
},
"occupied": {
"title": "Occupied",
"description": "Space occupancy. false = Unoccupied / true = Occupied.",
"type": "boolean"
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/occupied/boolean"
},
"minutesSinceLastOccupied": {
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/minutesSinceLastOccupied/minutes"
}
},
"required": ["occupancy", "occupied"]
}
"required": [
"occupancy",
"occupied"
]
}
17 changes: 17 additions & 0 deletions types/bosch/parkingLotSensor/uplink.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ function consume(event) {

if (port === 1 || port === 2 || port === 3) {
occupancy.occupied = !!occupancy.occupancy;
// Warm desk
const time = new Date().getTime();
const state = event.state || {};
occupancy.minutesSinceLastOccupied = 0; // Always give out minutesSinceLastOccupied for consistancy
if (occupancy.occupied) {
delete state.lastOccupancyTimestamp; // Delete last occupancy timestamp
} else if (state.lastOccupancyTimestamp !== undefined) {
occupancy.minutesSinceLastOccupied = Math.round((time - state.lastOccupancyTimestamp) / 1000 / 60); // Get free since
} else if (state.lastOccupiedValue) { //
state.lastOccupancyTimestamp = time; // Start with first no occupancy
}

if (Number.isNaN(occupancy.minutesSinceLastOccupied)) {
occupancy.minutesSinceLastOccupied = 0;
}
state.lastOccupiedValue = occupancy.occupied;
emit("state", state);
emit("sample", { data: occupancy, topic: "occupancy" });
}
}
93 changes: 91 additions & 2 deletions types/bosch/parkingLotSensor/uplink.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,132 @@ describe("Bosch Parking Lot Sensor Uplink", () => {
});

describe("consume()", () => {
it("should decode the Bosch Parking Lot Sensor payload", () => {
it("should decode the Bosch Parking Lot Sensor payload && state init", () => {
const data = {
data: {
port: 2,
payloadHex: "01",
},
};


utils.expectEmits((type, value) => {
assert.equal(type, "state");
assert.isNotNull(value);
assert.equal(value.lastOccupiedValue, true);
});

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
assert.typeOf(value.data, "object");
assert.equal(value.topic, "occupancy");
assert.equal(value.data.occupancy, 1);
assert.equal(value.data.occupied, true);
assert.equal(value.data.minutesSinceLastOccupied, 0);

utils.validateSchema(value.data, occupancySchema, { throwError: true });
});

consume(data);
});

it("should decode the Bosch Parking Lot Sensor payload and start the minutesSinceLastOccupied timer", () => {
const data = {
state: {
lastOccupiedValue: true
},
data: {
port: 2,
payloadHex: "00",
},
};

utils.expectEmits((type, value) => {
assert.equal(type, "state");
assert.isNotNull(value);
assert.equal(value.lastOccupiedValue, false);
// assert.equal(value.lastOccupancyTimestamp, new Date().getTime());
});

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
assert.typeOf(value.data, "object");

assert.equal(value.topic, "occupancy");
assert.equal(value.data.occupancy, 0);
assert.equal(value.data.occupied, false);
assert.equal(value.data.minutesSinceLastOccupied, 0);

utils.validateSchema(value.data, occupancySchema, { throwError: true });
});

consume(data);
});

it("should decode the Bosch Parking Lot Sensor payload", () => {
it("should decode the Bosch Parking Lot Sensor payload and get the minutesSinceLastOccupied time", () => {
const data = {
state: {
lastOccupiedValue: true,
lastOccupancyTimestamp: new Date().setMinutes(new Date().getMinutes() - 20)
},
data: {
port: 2,
payloadHex: "00",
},
};

utils.expectEmits((type, value) => {
assert.equal(type, "state");
assert.isNotNull(value);
assert.equal(value.lastOccupiedValue, false);
// assert.equal(value.lastOccupancyTimestamp, new Date().setMinutes(new Date().getMinutes() - 20));
});

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
assert.typeOf(value.data, "object");

assert.equal(value.topic, "occupancy");
assert.equal(value.data.occupancy, 0);
assert.equal(value.data.occupied, false);
assert.equal(value.data.minutesSinceLastOccupied, 20);

utils.validateSchema(value.data, occupancySchema, { throwError: true });
});

consume(data);
});

it("should decode the Bosch Parking Lot Sensor payload and delete the minutesSinceLastOccupied time", () => {
const data = {
state: {
lastOccupiedValue: true,
lastOccupancyTimestamp: new Date().setMinutes(new Date().getMinutes() - 20)
},
data: {
port: 2,
payloadHex: "01",
},
};

utils.expectEmits((type, value) => {
assert.equal(type, "state");
assert.isNotNull(value);
assert.equal(value.lastOccupiedValue, true);
});

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
assert.typeOf(value.data, "object");

assert.equal(value.topic, "occupancy");
assert.equal(value.data.occupancy, 1);
assert.equal(value.data.occupied, true);
assert.equal(value.data.minutesSinceLastOccupied, 0);

utils.validateSchema(value.data, occupancySchema, { throwError: true });
});
Expand Down
20 changes: 10 additions & 10 deletions types/bosch/parkingLotSensor0_39/occupancy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
"title": "Occupancy",
"properties": {
"occupancy": {
"title": "Occupancy",
"description": "Space occupancy. 0 = Unoccupied / 1 = Occupied.",
"type": "integer",
"minimum": 0,
"maximum": 1
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/occupancy/integer"
},
"occupied": {
"title": "Occupied",
"description": "Space occupancy. false = Unoccupied / true = Occupied.",
"type": "boolean"
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/occupied/boolean"
},
"minutesSinceLastOccupied": {
"$ref": "https://raw.githubusercontent.com/akenza-io/device-type-library/main/data-models/spaces/schema.json#/$defs/minutesSinceLastOccupied/minutes"
}
},
"required": ["occupancy", "occupied"]
}
"required": [
"occupancy",
"occupied"
]
}
Loading

0 comments on commit 854dd2c

Please sign in to comment.