bt-sensors-plugin-sk 1.3.5-1 → 1.3.6-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BTSensor.js +49 -4
- package/README.md +7 -1
- package/index.js +12 -1
- package/package.json +6 -5
- package/plugin_defaults.json +1 -1
- package/public/143.js +1 -1
- package/sensor_classes/Beacon/AbstractBeaconMixin.js +4 -4
- package/sensor_classes/ShellySBMO003Z.js +1 -1
- package/src/components/PluginConfigurationPanel.js +7 -8
package/BTSensor.js
CHANGED
|
@@ -319,11 +319,17 @@ class BTSensor extends EventEmitter {
|
|
|
319
319
|
type: "integer", default:30,
|
|
320
320
|
minimum: 10,
|
|
321
321
|
maximum: 600 },
|
|
322
|
-
|
|
322
|
+
|
|
323
323
|
params:{
|
|
324
324
|
title:`Device parameters`,
|
|
325
325
|
type:"object",
|
|
326
|
-
properties:{
|
|
326
|
+
properties:{
|
|
327
|
+
noContactThreshold: {title: "If no contact (in seconds), raise warning. Set to 0 to disable",
|
|
328
|
+
type: "integer",
|
|
329
|
+
minimum: 0,
|
|
330
|
+
maximum: 600,
|
|
331
|
+
default: 2*(this?.discoveryTimeout??30) },
|
|
332
|
+
}
|
|
327
333
|
},
|
|
328
334
|
paths:{
|
|
329
335
|
title:"Signalk Paths",
|
|
@@ -1065,7 +1071,7 @@ class BTSensor extends EventEmitter {
|
|
|
1065
1071
|
this._app.handleMessage(id,
|
|
1066
1072
|
{
|
|
1067
1073
|
updates:
|
|
1068
|
-
[{ meta: [{path: this.preparePath(path), value: { units: pathMeta?.unit, zones:pathMeta?.zones} }]}]
|
|
1074
|
+
[{ meta: [{path: this.preparePath(path), value: { units: pathMeta?.unit, zones:pathMeta?.zones } }]}]
|
|
1069
1075
|
})
|
|
1070
1076
|
}
|
|
1071
1077
|
})
|
|
@@ -1167,9 +1173,48 @@ class BTSensor extends EventEmitter {
|
|
|
1167
1173
|
|
|
1168
1174
|
);
|
|
1169
1175
|
}
|
|
1176
|
+
notifyNoContact(){
|
|
1177
|
+
this._app.handleMessage('bt-sensors-plugin-sk',
|
|
1178
|
+
{
|
|
1179
|
+
updates: [{
|
|
1180
|
+
$source: this.getName(),
|
|
1181
|
+
timestamp: (new Date()).toISOString(),
|
|
1182
|
+
values: [{
|
|
1183
|
+
path: `notifications.sensors.${this.macAndName()}`,
|
|
1184
|
+
value: {
|
|
1185
|
+
state: "warn",
|
|
1186
|
+
message: `No contact with sensor for ${this.elapsedTimeSinceLastContact()} seconds`,
|
|
1187
|
+
method: ["visual", "sound"]
|
|
1188
|
+
}
|
|
1189
|
+
}]
|
|
1190
|
+
}]
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
clearNoContact(){
|
|
1196
|
+
this._app.handleMessage('bt-sensors-plugin-sk',
|
|
1197
|
+
{
|
|
1198
|
+
updates: [{
|
|
1199
|
+
$source: this.getName(),
|
|
1200
|
+
timestamp: (new Date()).toISOString(),
|
|
1201
|
+
values: [{
|
|
1202
|
+
path: `notifications.sensors.${this.macAndName()}`,
|
|
1203
|
+
value: {
|
|
1204
|
+
state: "normal",
|
|
1205
|
+
message: `Communication with sensor normal`,
|
|
1206
|
+
method: []
|
|
1207
|
+
}
|
|
1208
|
+
}]
|
|
1209
|
+
}]
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1170
1215
|
getBatteryStrength(){
|
|
1171
1216
|
return this.getCurrentValue(this.constructor.batteryStrengthTag)
|
|
1172
1217
|
}
|
|
1173
1218
|
}
|
|
1174
1219
|
|
|
1175
|
-
module.exports = BTSensor
|
|
1220
|
+
module.exports = BTSensor
|
package/README.md
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## WHAT'S NEW
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Version 1.3.6
|
|
6
|
+
|
|
7
|
+
- New sensor parameter: no contact threshhold.
|
|
8
|
+
- Notification if no contact threshhold exceeded for sensor
|
|
9
|
+
- Smaller install footprint (moved rjsf dependencies to dev)
|
|
10
|
+
|
|
11
|
+
# Version 1.3.5
|
|
6
12
|
|
|
7
13
|
- Battery strength notification for supported sensors
|
|
8
14
|
- Battery strength value/icon displayed on config page
|
package/index.js
CHANGED
|
@@ -461,9 +461,12 @@ module.exports = function (app) {
|
|
|
461
461
|
sensor.on("debug", ()=>{
|
|
462
462
|
updateSensor(sensor)
|
|
463
463
|
})
|
|
464
|
+
sensor.on(sensor.constructor.batteryStrengthTag,()=>{
|
|
465
|
+
updateSensor(sensor)
|
|
466
|
+
})
|
|
464
467
|
sensor._lastRSSI=-1*Infinity
|
|
465
468
|
sensor.on("RSSI",(()=>{
|
|
466
|
-
if (Date.now()-sensor._lastRSSI >
|
|
469
|
+
if (Date.now()-sensor._lastRSSI > 10000) { //only update RSSI on client every 10 seconds
|
|
467
470
|
|
|
468
471
|
sensor._lastRSSI=Date.now()
|
|
469
472
|
|
|
@@ -785,6 +788,14 @@ module.exports = function (app) {
|
|
|
785
788
|
if (lc > dt) {
|
|
786
789
|
updateSensor(sensor)
|
|
787
790
|
}
|
|
791
|
+
if (sensor.noContactThreshold && lc>sensor.noContactThreshold){
|
|
792
|
+
if (sensor.isActive())
|
|
793
|
+
sensor.notifyNoContact()
|
|
794
|
+
}
|
|
795
|
+
else{
|
|
796
|
+
if (sensor.isActive())
|
|
797
|
+
sensor.clearNoContact()
|
|
798
|
+
}
|
|
788
799
|
})
|
|
789
800
|
if (sensorMap.size && options.inactivityTimeout && lastContactDelta > options.inactivityTimeout)
|
|
790
801
|
{
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bt-sensors-plugin-sk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6-1",
|
|
4
4
|
"description": "Bluetooth Sensors for Signalk - see https://www.npmjs.com/package/bt-sensors-plugin-sk#supported-sensors for a list of supported sensors",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
|
|
8
|
-
"@rjsf/core": "^5.24.11",
|
|
9
|
-
"@rjsf/utils": "^5.24.11",
|
|
10
|
-
"@rjsf/validator-ajv8": "^5.24.11",
|
|
7
|
+
|
|
11
8
|
"better-sse": "^0.14.1",
|
|
12
9
|
"buffer": "^6.0.3",
|
|
13
10
|
"@jellybrick/dbus-next": "^0.10.3",
|
|
@@ -18,6 +15,10 @@
|
|
|
18
15
|
"lru-cache": "^11.1.0"
|
|
19
16
|
},
|
|
20
17
|
"devDependencies": {
|
|
18
|
+
"@rjsf/bootstrap-4": "^5.24.12",
|
|
19
|
+
"@rjsf/core": "^5.24.11",
|
|
20
|
+
"@rjsf/utils": "^5.24.11",
|
|
21
|
+
"@rjsf/validator-ajv8": "^5.24.11",
|
|
21
22
|
"@babel/core": "^7.11.6",
|
|
22
23
|
"@babel/preset-react": "^7.10.4",
|
|
23
24
|
"@fortawesome/fontawesome-free": "^5.15.1",
|
package/plugin_defaults.json
CHANGED
package/public/143.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[143],{9337:()=>{},62995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{BTConfig:()=>$,default:()=>D});var a=n(73490),s=n(74810),r=n(40334),o=n(86528),i=n.n(o),c=n(11363),l=n(97493),u=n(27606),m=n(82096),d=n(55877),f=n(3768),g=n(71431),h=n(39676),p=n(47041),E=n(86038),y=n(95027),w=n(26067),S=n(43540),
|
|
1
|
+
(self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[143],{9337:()=>{},62995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{BTConfig:()=>$,default:()=>D});var a=n(73490),s=n(74810),r=n(40334),o=n(86528),i=n.n(o),c=n(11363),l=n(97493),u=n(27606),m=n(82096),d=n(55877),f=n(3768),g=n(71431),h=n(39676),p=n(47041),E=n(86038),y=n(95027),w=n(26067),S=n(43540),v=n(38250),b=n(31008),A=n(20455),C=n(23399);const k=e=>console.log.bind(console,e);function $(e){const t=(0,m.A)((e=>({root:{"& > *":{margin:e.spacing(1)}}}))),[n,$]=(0,o.useState)({}),[D,_]=(0,o.useState)({}),[x,T]=(0,o.useState)({}),[N,O]=(0,o.useState)({"ui:options":{label:!1},paths:{enableMarkdownInDescription:!0},title:{"ui:widget":"hidden"}}),[j,M]=(0,o.useState)(),[U,R]=(0,o.useState)(!1),[B,J]=(0,o.useState)(!0),[L,I]=(0,o.useState)(new Map),[P,W]=(0,o.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[z,K]=(0,o.useState)("unknown"),[F,G]=(0,o.useState)(),[H,Y]=(0,o.useState)(!1),[q,Q]=(0,o.useState)(""),V=t();function X(e,t){const n=new Headers;return n.append("Content-Type","application/json"),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include",method:"POST",body:JSON.stringify(t),headers:n})}async function Z(e,t={}){let n;try{const a=Object.keys(t).length?"?"+new URLSearchParams(t).toString():"";n=await fetch(`/plugins/bt-sensors-plugin-sk/${e}${a}`,{credentials:"include",method:"GET"})}catch(e){n={status:500,statusText:e.toString()}}return n}function ee(e){return Object.keys(e.configCopy).length>0}function te(e){const t=ee(e);return i().createElement(A.A,{action:!0,onClick:()=>{e.config.mac_address=e.info.mac,T(e.schema),M(e.config)}},i().createElement("div",{class:"d-flex justify-content-between"},i().createElement("div",{class:"d-flex",style:t?{fontWeight:"normal"}:{fontStyle:"italic"}},`${e._changesMade?"*":""}${e.info.name} MAC: ${e.info.mac} RSSI: ${n=e.info.RSSI,null==n?NaN:n} ${function(e){const t=e.info?.batteryStrength;return t?`BATT: ${100*t}%`:""}(e)}`,function(e){const t=e.info.batteryStrength;return void 0===t?"":i().createElement(w.A,{size:22,orientation:"vertical",customization:{batteryBody:{fill:"silver",strokeColor:"silver",strokeWidth:2},batteryCap:{fill:"silver",strokeColor:"silver",cornerRadius:3,strokeWidth:0,capToBodyRatio:.4},readingText:{lightContrastColor:"purple",darkContrastColor:"yellow",lowBatteryColor:"red",fontFamily:"Arial",fontSize:16}},value:100*t})}(e)),i().createElement("div",{class:"d-flex "},`${e.info.state} ${e.info.error?" (ERROR)":""}`,function(e){return e.info.connected?i().createElement(d.A,null):null==e.info.lastContactDelta||e.info.lastContactDelta>e.config.discoveryTimeout?i().createElement(f.A,null):e.info.signalStrength>80?i().createElement(g.A,null):e.info.signalStrength>60?i().createElement(h.A,null):e.info.signalStrength>40?i().createElement(p.A,null):e.info.signalStrength>20?i().createElement(E.A,null):i().createElement(y.A,null)}(e))));var n}function ne(e){window.open(e,"_blank","noreferrer")}return(0,o.useEffect)((()=>{let e=null;return Z("getPluginState").then((async t=>{if(404==t.status)throw K("unknown"),new Error("unable to get plugin state");const n=await t.json();e=new EventSource("/plugins/bt-sensors-plugin-sk/sse",{withCredentials:!0}),e.addEventListener("newsensor",(e=>{!function(e){let t=JSON.parse(e.data);console.log(`New sensor: ${t.info.mac}`),I((e=>(e.set(t.info.mac,t),new Map(e))))}(e)})),e.addEventListener("sensorchanged",(e=>{!function(e){console.log("sensorchanged");const t=JSON.parse(e.data);console.log(t),I((e=>{const n=e.get(t.mac);return n&&Object.assign(n.info,t),new Map(e)}))}(e)})),e.addEventListener("progress",(e=>{const t=JSON.parse(e.data);W(t)})),e.addEventListener("pluginstate",(e=>{const t=JSON.parse(e.data);K(t.state)})),K(n.state),(async()=>{const e=await async function(){const e=await Z("getSensors");if(200!=e.status)throw new Error(`Unable get sensor data: ${e.statusText} (${e.status}) `);return await e.json()}();I(new Map(e.map((e=>[e.info.mac,e]))))})()})).catch((e=>{G(e.message)})),()=>{console.log("Closing connection to SSE"),e.close()}}),[]),(0,o.useEffect)((()=>{if(!U)return;if(!j||!L)return;const e=L.get(j.mac_address);e&&x&&j&&Object.hasOwn(j,"params")&&"UNKNOWN"==e.info.class&&j.params.sensorClass&&"UNKNOWN"!=j.params.sensorClass&&(J(!1),Q(`Please wait. Fetching schema for ${j.params.sensorClass}...`),async function(e,t){const n=await Z("getSensorInfo",{mac_address:e,class:t});if(200!=n.status)throw new Error(`Unable get sensor info: ${n.statusText} (${n.status}) `);return await n.json()}(j.mac_address,j.params.sensorClass).then((e=>{T(e.schema)})).catch((e=>{alert(e.message)})).finally((()=>{Q(""),J(!0),R(!1)})))}),[U]),(0,o.useEffect)((()=>{Y(""!=q)}),[q]),(0,o.useEffect)((()=>{"started"==z?(async function(){const e=await Z("getBaseData");if(200!=e.status)throw new Error(`Unable to get base data: ${e.statusText} (${e.status}) `);const t=await e.json();return t.schema.htmlDescription=i().createElement("div",null,(0,r.Ay)(t.schema.htmlDescription),i().createElement("p",null)),t}().then((e=>{$(e.schema),_(e.data)})).catch((e=>{G(e.message)})),async function(){const e=await Z("getProgress");if(200!=e.status)throw new Error(`Unable to get progress: ${e.statusText} (${e.status}) `);return await e.json()}().then((e=>{W(e)})).catch((e=>{G(e.message)}))):($({}),_({}))}),[z]),"stopped"==z||"unknown"==z?i().createElement("h3",null,"Enable plugin to see configuration"):i().createElement("div",null,i().createElement(c.A,{anchorOrigin:{horizontal:"center",vertical:"bottom"},onClose:()=>Y(!1),open:H,message:q,key:"snackbar"}),i().createElement("div",{className:V.root},i().createElement(l.A,{variant:"contained",onClick:()=>{ne("https://github.com/naugehyde/bt-sensors-plugin-sk/tree/1.2.0-beta#configuration")}},"Documentation"),i().createElement(l.A,{variant:"contained",onClick:()=>{ne("https://github.com/naugehyde/bt-sensors-plugin-sk/issues/new/choose")}},"Report Issue"),i().createElement(l.A,{variant:"contained",onClick:()=>{ne("https://discord.com/channels/1170433917761892493/1295425963466952725")}},"Discord Thread"),i().createElement("p",null),i().createElement("p",null)),i().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),F?i().createElement("h2",{style:{color:"red"}},F):"",i().createElement(a.Ay,{schema:n,validator:s.Ay,uiSchema:{"ui:field":"LayoutGridField","ui:layoutGrid":{"ui:row":[{"ui:row":{className:"row",children:[{"ui:columns":{className:"col-xs-4",children:["adapter","transport","duplicateData","discoveryTimeout","discoveryInterval"]}}]}}]}},onChange:e=>_(e.formData),onSubmit:({formData:e},t)=>{var n;n=e,I(new Map),X("updateBaseData",n).then((e=>{200!=e.status&&G(`Unable to update base data: ${e.statusText} (${e.status})`)})),T({})},onError:k("errors"),formData:D}),i().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),i().createElement("p",null),i().createElement("p",null),P.deviceCount<P.totalDevices?i().createElement(C.A,{max:P.maxTimeout,now:P.progress}):"",i().createElement("p",null),i().createElement(v.A,{defaultActiveKey:"_configured",id:"domain-tabs",className:"mb-3"},function(){const e=[...new Set([...L.entries()].map((e=>e[1].info.domain)))].sort(),t=Array.from(L.entries()).filter((e=>ee(e[1])));let n={};return n._configured=0==t.length?"Select a device from its domain tab (Electrical etc.) and configure it.":t.map((e=>te(L.get(e[0])))),e.forEach((e=>{var t;n[e]=(t=e,Array.from(L.entries()).filter((e=>e[1].info.domain===t))).map((e=>te(L.get(e[0]))))})),Object.keys(n).map((e=>function(e,t){let n=e.slice("_"===e.charAt(0)?1:0);return i().createElement(b.A,{eventKey:e,title:`${n.charAt(0).toUpperCase()}${n.slice(1)}${"string"==typeof t?"":" ("+t.length+")"}`},i().createElement(S.A,{style:{maxHeight:"300px",overflowY:"auto"}},t))}(e,n[e])))}()),i().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys(x).length?"none":""}},i().createElement(u.A,{container:!0,direction:"column",style:{spacing:5}},i().createElement(u.A,{item:!0},i().createElement("h2",null,x?.title),i().createElement("p",null)),i().createElement(u.A,{item:!0},(0,r.Ay)(x?.htmlDescription))),i().createElement("fieldset",{disabled:!B},i().createElement(a.Ay,{schema:x,validator:s.Ay,uiSchema:N,onChange:(e,t)=>{const n=L.get(e.formData.mac_address);n&&(n._changesMade=!0,n.config=e.formData,M(e.formData)),"root_params_sensorClass"==t&&R(!0)},onSubmit:({formData:e},t)=>{var n;X("updateSensorData",n=e).then((e=>{if(200!=e.status)throw new Error(e.statusText);I((e=>(e.delete(n.mac_address),new Map(e)))),T({})})),alert("Changes saved")},onError:k("errors"),formData:j},i().createElement("div",{className:V.root},i().createElement(l.A,{type:"submit",color:"primary",variant:"contained"},"Save"),i().createElement(l.A,{variant:"contained",onClick:()=>{var e;e=j.mac_address,L.get(e)._changesMade=!1,L.get(e).config=JSON.parse(JSON.stringify(L.get(e).configCopy)),M(L.get(e).config)}},"Undo"),i().createElement(l.A,{variant:"contained",color:"secondary",onClick:e=>function(e){const t=L.get(e);(!ee(t)||window.confirm(`Delete configuration for ${t.info.name}?`))&&function(e){try{X("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),I((t=>(t.delete(e),new Map(t)))),T({})}catch{}}(e)}(j.mac_address)},"Delete"))))))}const D=$}}]);
|
|
@@ -43,7 +43,7 @@ class AbstractBeaconMixin {
|
|
|
43
43
|
}
|
|
44
44
|
)
|
|
45
45
|
this.addParameter(
|
|
46
|
-
"
|
|
46
|
+
"presenceThreshold",
|
|
47
47
|
{
|
|
48
48
|
title:'distance in meters beyond which presence on board should not be presumed',
|
|
49
49
|
type: 'integer',
|
|
@@ -51,7 +51,7 @@ class AbstractBeaconMixin {
|
|
|
51
51
|
}
|
|
52
52
|
)
|
|
53
53
|
this.addParameter(
|
|
54
|
-
"
|
|
54
|
+
"lastContactThreshold",
|
|
55
55
|
{
|
|
56
56
|
title:'time in seconds beyond which presence on board should not be presumed',
|
|
57
57
|
type: 'integer',
|
|
@@ -69,7 +69,7 @@ class AbstractBeaconMixin {
|
|
|
69
69
|
|
|
70
70
|
}
|
|
71
71
|
elapsedTimeSinceLastContact(lc){
|
|
72
|
-
if (Number.isNaN(lc) || lc > this.
|
|
72
|
+
if (Number.isNaN(lc) || lc > this.lastContactThreshold){
|
|
73
73
|
this.emit("onBoard",false)
|
|
74
74
|
}
|
|
75
75
|
return lc
|
|
@@ -84,7 +84,7 @@ class AbstractBeaconMixin {
|
|
|
84
84
|
const distances= getDistances(this.constructor.DistanceManagerSingleton, mac, this.getTxPower(), rssi)
|
|
85
85
|
if (distances){
|
|
86
86
|
this.emit("approxDistance", distances)
|
|
87
|
-
this.emit("onBoard", distances.avgDistance<this?.
|
|
87
|
+
this.emit("onBoard", distances.avgDistance<this?.presenceThreshold??20)
|
|
88
88
|
}
|
|
89
89
|
if (this._position){
|
|
90
90
|
this.GPSLog.unshift(
|
|
@@ -421,21 +421,20 @@ function createListGroupItem(sensor){
|
|
|
421
421
|
setSensorData(sensor.config)
|
|
422
422
|
}
|
|
423
423
|
}>
|
|
424
|
-
<div
|
|
424
|
+
<div class="d-flex justify-content-between">
|
|
425
|
+
<div class="d-flex" style={config?{fontWeight:"normal"}:{fontStyle:"italic"}}>
|
|
425
426
|
{`${sensor._changesMade?"*":""}${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)} ${batteryStrength(sensor)}` }
|
|
426
|
-
|
|
427
|
-
|
|
427
|
+
{batteryIcon(sensor)}
|
|
428
|
+
</div>
|
|
429
|
+
<div class="d-flex ">
|
|
428
430
|
{
|
|
429
431
|
`${sensor.info.state} ${sensor.info.error?" (ERROR)": "" }`
|
|
430
432
|
}
|
|
431
|
-
|
|
433
|
+
|
|
432
434
|
{
|
|
433
435
|
signalStrengthIcon(sensor)
|
|
434
436
|
}
|
|
435
|
-
|
|
436
|
-
batteryIcon(sensor)
|
|
437
|
-
}
|
|
438
|
-
</div>
|
|
437
|
+
|
|
439
438
|
|
|
440
439
|
</div>
|
|
441
440
|
</div>
|