Skip to content

Commit

Permalink
Added warm desk logic for all devices which send occupancy
Browse files Browse the repository at this point in the history
  • Loading branch information
J2thatsme committed Dec 12, 2024
1 parent e5096a0 commit 768d4e7
Show file tree
Hide file tree
Showing 65 changed files with 994 additions and 213 deletions.
2 changes: 1 addition & 1 deletion data-models/spaces/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,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
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/occupancy"
},
"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"
]
}
18 changes: 18 additions & 0 deletions types/bosch/parkingLotSensor/uplink.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ 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 freeSincce 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.lastOccupancyValue) { //
state.lastOccupancyTimestamp = time; // Start with first no occupancy
}

if (Number.isNaN(occupancy.minutesSinceLastOccupied)) {
occupancy.minutesSinceLastOccupied = 0;
}
state.lastOccupancyValue = 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.lastOccupancyValue, 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: {
lastOccupancyValue: true
},
data: {
port: 2,
payloadHex: "00",
},
};

utils.expectEmits((type, value) => {
assert.equal(type, "state");
assert.isNotNull(value);
assert.equal(value.lastOccupancyValue, 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: {
lastOccupancyValue: 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.lastOccupancyValue, 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: {
lastOccupancyValue: 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.lastOccupancyValue, 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/occupancy"
},
"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"
]
}
20 changes: 20 additions & 0 deletions types/bosch/parkingLotSensor0_39/uplink.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ function consume(event) {
if (port === 1 || port === 2) {
occupancy.occupancy = Bits.bitsToUnsigned(bits.substr(0, 8));
occupancy.occupied = !!occupancy.occupancy;

// Warm desk
const time = new Date().getTime();
const state = event.state || {};
occupancy.minutesSinceLastOccupied = 0; // Always give out freeSincce 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.lastOccupancyValue) { //
state.lastOccupancyTimestamp = time; // Start with first no occupancy
}

if (Number.isNaN(occupancy.minutesSinceLastOccupied)) {
occupancy.minutesSinceLastOccupied = 0;
}
state.lastOccupancyValue = occupancy.occupied;
emit("state", state);
//

if (payload.length > 2) {
data.temperature = Bits.bitsToSigned(bits.substr(8, 8));
emit("sample", { data, topic: "lifecycle" });
Expand Down
12 changes: 12 additions & 0 deletions types/bosch/parkingLotSensor0_39/uplink.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ describe("Bosch Parking Lot Sensor Uplink", () => {
},
};

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

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
Expand All @@ -60,6 +66,12 @@ describe("Bosch Parking Lot Sensor Uplink", () => {
},
};

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

utils.expectEmits((type, value) => {
assert.equal(type, "sample");
assert.isNotNull(value);
Expand Down
14 changes: 9 additions & 5 deletions types/decentlab/IAM/occupancy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@
"type": "boolean"
},
"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 768d4e7

Please sign in to comment.