bt-sensors-plugin-sk 1.2.0-beta.0.0.8 → 1.2.0-beta.0.1.0

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.
@@ -1,6 +1,8 @@
1
1
  const BTSensor = require("../BTSensor");
2
2
 
3
3
  class SwitchBotTH extends BTSensor {
4
+ static Domain = BTSensor.SensorDomains.environmental
5
+
4
6
  static async test(){
5
7
 
6
8
  const p = {[this.ID.toString()]: [0xd8, 0x35, 0x34, 0x38, 0x4f, 0x70, 0x07, 0x02, 0x04, 0x96, 0x2c, 0x00]}
@@ -1,5 +1,7 @@
1
1
  const BTSensor = require("../BTSensor");
2
2
  class UltrasonicWindMeter extends BTSensor{
3
+ static Domain = BTSensor.SensorDomains.environmental
4
+
3
5
  static async identify(device){
4
6
 
5
7
  const uuids = await this.getDeviceProp(device,'UUIDs')
@@ -12,6 +14,9 @@ class UltrasonicWindMeter extends BTSensor{
12
14
  hasGATT(){
13
15
  return true
14
16
  }
17
+ usingGATT(){
18
+ return true
19
+ }
15
20
  emitGATT(){
16
21
  this.battCharacteristic.readValue()
17
22
  .then((buffer)=>
@@ -29,6 +34,7 @@ class UltrasonicWindMeter extends BTSensor{
29
34
  }
30
35
  initSchema(){
31
36
  super.initSchema()
37
+ this.getGATTParams()["useGATT"].default=true
32
38
  this.addDefaultPath("batt",'sensors.batteryStrength')
33
39
  .read=(buffer)=>{return (buffer.readUInt8())/100}
34
40
 
@@ -9,6 +9,7 @@ function sleep(x) {
9
9
  });
10
10
  }
11
11
  class VictronSensor extends BTSensor{
12
+ static Domain = BTSensor.SensorDomains.electrical
12
13
 
13
14
  constructor(device,config,gattConfig){
14
15
  super(device,config,gattConfig)
@@ -19,13 +19,13 @@ class VictronInverterRS extends VictronSensor{
19
19
 
20
20
  const md = this.addMetadatum('chargerError','', 'charger error',
21
21
  (buff)=>{return VC.ChargerError(buff.readIntU8(1))})
22
- .default='electrical.inverters.{id}.error'
22
+ md.default='electrical.inverters.{id}.error'
23
23
  md.notify=true
24
24
 
25
25
  this.addMetadatum('batteryVoltage','V', 'battery voltage',
26
26
  (buff)=>{return this.NaNif(buff.readInt16LE(2),0x7FFF)/100})
27
27
  .default='electrical.inverters.{id}.battery.voltage'
28
-
28
+ .
29
29
  this.addMetadatum('pvPower','W', 'PV power',
30
30
  (buff)=>{return this.NaNif(buff.readUInt16LE(4), 0xffff)})
31
31
  .default='electrical.inverters.{id}.power'
@@ -71,7 +71,8 @@ const DEVICE_TYPES = new Map([
71
71
  ]);
72
72
 
73
73
  class XiaomiMiBeacon extends BTSensor{
74
-
74
+ static Domain = BTSensor.SensorDomains.environmental
75
+
75
76
  constructor(device, config, gattConfig){
76
77
  super(device, config, gattConfig)
77
78
  this.encryptionKey = config?.encryptionKey
@@ -10,12 +10,14 @@ import { SignalCellular0Bar, SignalCellular1Bar, SignalCellular2Bar, SignalCellu
10
10
  const log = (type) => console.log.bind(console, type);
11
11
 
12
12
  import ListGroup from 'react-bootstrap/ListGroup';
13
+ import Tabs from 'react-bootstrap/Tabs';
14
+ import Tab from 'react-bootstrap/Tab';
13
15
  import { ListGroupItem } from 'react-bootstrap';
14
16
 
15
17
  import ProgressBar from 'react-bootstrap/ProgressBar';
16
18
 
17
19
 
18
- var _sensorMap
20
+ var _sensorMap, _sensorDomains={}, _sensorList={}
19
21
 
20
22
  export default (props) => {
21
23
 
@@ -47,7 +49,6 @@ export default (props) => {
47
49
 
48
50
  const [pluginState, setPluginState ] = useState("unknown")
49
51
  const [error, setError ] = useState()
50
-
51
52
 
52
53
  function sendJSONData(cmd, data){
53
54
 
@@ -65,16 +66,16 @@ export default (props) => {
65
66
 
66
67
  async function fetchJSONData(path){
67
68
  console.log(`fetching ${path}`)
68
-
69
+
69
70
  return fetch(`/plugins/bt-sensors-plugin-sk/${path}`, {
70
71
  credentials: 'include'
71
72
  })
72
73
 
73
74
  }
74
75
 
75
- async function getSensorData(){
76
-
77
- const response = await fetchJSONData("sensors")
76
+ async function getSensors(){
77
+ console.log("getSensors")
78
+ const response = await fetchJSONData("getSensors")
78
79
  if (response.status!=200){
79
80
  throw new Error(`Unable get sensor data: ${response.statusText} (${response.status}) `)
80
81
  }
@@ -83,10 +84,20 @@ export default (props) => {
83
84
  return json
84
85
 
85
86
  }
87
+ async function getDomains(){
88
+ console.log("getDomains")
89
+ const response = await fetchJSONData("getDomains")
90
+ if (response.status!=200){
91
+ throw new Error(`Unable get domain data: ${response.statusText} (${response.status}) `)
92
+ }
93
+ const json = await response.json()
94
+ console.log(json)
95
+ return json
86
96
 
97
+ }
87
98
  async function getBaseData(){
88
-
89
- const response = await fetchJSONData("base")
99
+ console.log("getBaseData")
100
+ const response = await fetchJSONData("getBaseData")
90
101
  if (response.status!=200){
91
102
  throw new Error(`Unable get base data: ${response.statusText} (${response.status}) `)
92
103
  }
@@ -95,8 +106,8 @@ export default (props) => {
95
106
  return json
96
107
  }
97
108
  async function getProgress(){
98
-
99
- const response = await fetchJSONData("progress")
109
+ console.log("getProgress")
110
+ const response = await fetchJSONData("getProgress")
100
111
  if (response.status!=200){
101
112
  throw new Error(`Unable get progres: ${response.statusText} (${response.status}) `)
102
113
  }
@@ -106,7 +117,8 @@ export default (props) => {
106
117
  }
107
118
 
108
119
  function updateSensorData(data){
109
- sendJSONData("sendSensorData", data).then((response)=>{
120
+ console.log("updateSensorData")
121
+ sendJSONData("updateSensorData", data).then((response)=>{
110
122
  if (response.status != 200) {
111
123
  throw new Error(response.statusText)
112
124
  }
@@ -114,14 +126,17 @@ export default (props) => {
114
126
  sensorMap.get(data.mac_address).config = data
115
127
 
116
128
  })
117
- }
129
+ }
118
130
 
119
131
  function undoChanges(mac) {
132
+ console.log("undoChanges")
120
133
  sensorMap.get(mac)._changesMade = false
121
134
  setSensorData( sensorMap.get(mac).config )
122
135
  }
123
136
 
124
137
  function removeSensorData(mac){
138
+ console.log("removeSensorData")
139
+
125
140
  try{
126
141
 
127
142
  sendJSONData("removeSensorData", {mac_address:mac} ).then((response)=>{
@@ -142,7 +157,9 @@ export default (props) => {
142
157
 
143
158
 
144
159
  function updateBaseData(data){
145
- sendJSONData("sendBaseData", data).then( (response )=>{
160
+ console.log("updateBaseData")
161
+
162
+ sendJSONData("updateBaseData", data).then( (response )=>{
146
163
  if (response.status != 200) {
147
164
  setError(new Error(`Unable to update base data: ${response.statusText} (${response.status})`))
148
165
  } else {
@@ -160,7 +177,7 @@ export default (props) => {
160
177
  function refreshSensors(){
161
178
  console.log('refreshing sensor map')
162
179
 
163
- getSensorData().then((sensors)=>{
180
+ getSensors().then((sensors)=>{
164
181
  setSensorMap (new Map(sensors.map((sensor)=>[sensor.info.mac,sensor])));
165
182
  })
166
183
  .catch((e)=>{
@@ -170,14 +187,23 @@ export default (props) => {
170
187
 
171
188
 
172
189
  useEffect(()=>{
173
-
174
- fetchJSONData("sendPluginState").then( async (response)=> {
190
+ console.log("useEffect([])")
191
+ fetchJSONData("getPluginState").then( async (response)=> {
192
+ if (response.status==404) {
193
+ setPluginState("unknown")
194
+ throw new Error("unable to get plugin state")
195
+ }
175
196
  const json = await response.json()
176
197
  setPluginState(json.state)
198
+
199
+
200
+ _sensorDomains = await getDomains()
201
+
177
202
  console.log("Setting up eventsource")
178
203
  const eventSource = new EventSource("/plugins/bt-sensors-plugin-sk/sse")
179
204
 
180
205
  eventSource.addEventListener("newsensor", (event) => {
206
+ console.log("newsensor")
181
207
  let json = JSON.parse(event.data)
182
208
 
183
209
  if (!_sensorMap.has(json.info.mac)) {
@@ -187,7 +213,9 @@ export default (props) => {
187
213
  });
188
214
 
189
215
  eventSource.addEventListener("sensorchanged", (event) => {
190
- let json = JSON.parse(event.data)
216
+ let json = JSON.parse(event.data)
217
+ console.log("sensorchanged")
218
+ console.log(json)
191
219
 
192
220
  if (_sensorMap.has(json.mac)) {
193
221
  let sensor = _sensorMap.get(json.mac)
@@ -196,12 +224,14 @@ export default (props) => {
196
224
  }
197
225
  });
198
226
  eventSource.addEventListener("progress", (event) => {
227
+ console.log("progress")
199
228
  const json = JSON.parse(event.data)
200
229
  setProgress(json)
201
230
  console.log(json)
202
231
  });
203
232
 
204
233
  eventSource.addEventListener("pluginstate", (event) => {
234
+ console.log("pluginstate")
205
235
  const json = JSON.parse(event.data)
206
236
  setPluginState(json.state)
207
237
  });
@@ -215,6 +245,7 @@ export default (props) => {
215
245
  },[])
216
246
 
217
247
  useEffect(()=>{
248
+ console.log("useEffect([pluginState])")
218
249
  if (pluginState=="started"){
219
250
  refreshSensors()
220
251
 
@@ -239,9 +270,7 @@ useEffect(()=>{
239
270
 
240
271
  },[pluginState])
241
272
 
242
- useEffect(()=>{
243
- console.log(error)
244
- },[error])
273
+
245
274
 
246
275
  function confirmDelete(mac){
247
276
  const result = window.confirm(`Delete configuration for ${mac}?`)
@@ -268,27 +297,21 @@ function signalStrengthIcon(sensor){
268
297
  return <SignalCellular0Bar/>
269
298
 
270
299
  }
271
- useEffect(()=>{
272
- _sensorMap = sensorMap
273
-
274
- setSensorList(
275
-
276
- Array.from(sensorMap.entries()).map((entry) => {
277
- const sensor = sensorMap.get(entry[0]);
278
- const config= sensor.config
279
- const hasConfig = Object.keys(config).length>0;
280
-
281
-
282
- return <ListGroupItem action
300
+ function hasConfig(sensor){
301
+ return Object.keys(sensor.config).length>0;
302
+ }
303
+
304
+ function createListGroupItem(sensor){
305
+
306
+ const config = hasConfig(sensor)
307
+ return <ListGroupItem action
283
308
  onClick={()=>{
284
- if (sensor){
285
- config.mac_address=entry[0]
309
+ sensor.config.mac_address=sensor.info.mac
286
310
  setSchema(sensor.schema)
287
- setSensorData(config)
288
- }
311
+ setSensorData(sensor.config)
289
312
  }
290
313
  }>
291
- <div class="d-flex justify-content-between align-items-center" style={hasConfig?{fontWeight:"normal"}:{fontStyle:"italic"}}>
314
+ <div class="d-flex justify-content-between align-items-center" style={config?{fontWeight:"normal"}:{fontStyle:"italic"}}>
292
315
  {`${sensor._changesMade?"*":""}${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
293
316
  <div class="d-flex justify-content-between ">
294
317
  {
@@ -297,9 +320,37 @@ useEffect(()=>{
297
320
  </div>
298
321
  </div>
299
322
  </ListGroupItem>
300
- })
301
- )
302
-
323
+ }
324
+
325
+ function configuredDevices(){
326
+ return Array.from(sensorMap.entries()).filter((entry)=>hasConfig(entry[1]))
327
+ }
328
+
329
+ function devicesInDomain(domain){
330
+ return Array.from(sensorMap.entries()).filter((entry)=>entry[1].info.domain===domain)
331
+ }
332
+
333
+
334
+ useEffect(()=>{
335
+ console.log("useEffect([sensorMap])")
336
+
337
+ _sensorMap = sensorMap
338
+
339
+ const _sensorDomains = new Set(sensorMap.entries().map((entry)=>{ return entry[1].info.domain}))
340
+ const sl = {
341
+ _configured: configuredDevices().map((entry) => {
342
+ return createListGroupItem(sensorMap.get(entry[0]))
343
+ })
344
+ }
345
+
346
+ _sensorDomains.forEach((d)=>{
347
+ sl[d]=devicesInDomain(d).map((entry) => {
348
+ return createListGroupItem(sensorMap.get(entry[0]))
349
+ })
350
+ })
351
+ _sensorList=sl
352
+
353
+
303
354
  },[sensorMap]
304
355
  )
305
356
 
@@ -307,18 +358,71 @@ useEffect(()=>{
307
358
  return value==null? NaN : value
308
359
  }
309
360
 
310
-
311
- if (pluginState=="stopped")
312
- return (<h1 >Enable plugin to see configuration</h1>)
361
+ function getSensorList(domain){
362
+ return _sensorList[domain]
363
+ }
364
+
365
+ function getTabs(){
366
+
367
+ return Object.keys(_sensorList).map((domain)=> {return getTab(domain)})
368
+ }
369
+ function getTab(key){
370
+ var title = key.slice(key.charAt(0)==="_"?1:0)
371
+
372
+ return <Tab eventKey={key} title={title.charAt(0).toUpperCase()+title.slice(1) }>
373
+
374
+ <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
375
+ <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
376
+ {getSensorList(key)}
377
+ </ListGroup>
378
+
379
+ <div style= {{ paddingLeft: 10, paddingTop: 10, display: (Object.keys(schema).length==0)? "none" :"" }} >
380
+
381
+ <Form
382
+ schema={schema}
383
+ validator={validator}
384
+ uiSchema={uiSchema}
385
+ onChange={(e) => {
386
+ const s = sensorMap.get(e.formData.mac_address)
387
+ s._changesMade=true
388
+ setSensorData(e.formData)
389
+ }
390
+ }
391
+ onSubmit={({ formData }, e) => {
392
+ console.log(formData)
393
+ updateSensorData(formData)
394
+ setSchema({})
395
+ alert("Changes saved")
396
+ }}
397
+ onError={log('errors')}
398
+ formData={sensorData}>
399
+ <div>
400
+ <Grid direction="row" style={{spacing:5}}>
401
+ <Button type='submit' color="primary" variant="contained">Save</Button>
402
+ <Button variant="contained" onClick={()=>{undoChanges(sensorData.mac_address)}}>Undo</Button>
403
+ <Button variant="contained" color="secondary" onClick={(e)=>confirmDelete(sensorData.mac_address)}>Delete</Button>
404
+
405
+ </Grid>
406
+ </div>
407
+ </Form>
408
+
409
+ </div>
410
+ </div>
411
+ </Tab>
412
+ }
413
+
414
+ if (pluginState=="stopped" || pluginState=="unknown")
415
+ return (<h1 >Enable plugin to see configuration (if plugin is Enabled and you're seeing this message, restart SignalK)</h1>)
313
416
  else
314
417
  return(
418
+
315
419
  <div>
316
- {error?<h2 style="color: red;">{error.message}</h2>:""}
420
+ {error?<h2 style="color: red;">{error}</h2>:""}
317
421
  <Form
318
422
  schema={baseSchema}
319
423
  validator={validator}
320
424
  onChange={(e) => setBaseData(e.formData)}
321
- onSubmit={ ({ formData }, e) => {setSensorData(null); updateBaseData(formData) }}
425
+ onSubmit={ ({ formData }, e) => { updateBaseData(formData); setSchema({}) } }
322
426
  onError={log('errors')}
323
427
  formData={baseData}
324
428
  />
@@ -329,46 +433,16 @@ useEffect(()=>{
329
433
  now={progress.progress}
330
434
  />:""
331
435
  }
332
- <h2>{`${sensorMap.size>0?"Bluetooth Devices click to configure" :""}`}</h2>
333
- <h2>{`${sensorMap.size>0?"(* means sensor has unsaved changes)" :""}`}</h2>
436
+ <h2>{`${sensorMap.size>0?"Bluetooth Devices - Select to configure" :""}`}</h2>
437
+ <h2>{`${sensorMap.size>0?"(* = sensor has unsaved changes)" :""}`}</h2>
334
438
  <p></p>
335
- <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
336
- <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
337
- {sensorList}
338
- </ListGroup>
339
- <div style= {{ paddingLeft: 10, paddingTop: 10, display: (Object.keys(schema).length==0)? "none" :"" }} >
340
- <Form
341
- schema={schema}
342
- validator={validator}
343
- uiSchema={uiSchema}
344
- onChange={(e) => {
345
- const s = sensorMap.get(e.formData.mac_address)
346
- s._changesMade=true
347
- //s.config = e.formData;
348
-
349
- setSensorData(e.formData)
350
- }
351
- }
352
- onSubmit={({ formData }, e) => {
353
- console.log(formData)
354
- updateSensorData(formData)
355
- setSchema({})
356
- alert("Changes saved")
357
- }}
358
- onError={log('errors')}
359
- formData={sensorData}>
360
- <div>
361
- <Grid direction="row" style={{spacing:5}}>
362
- <Button type='submit' color="primary" variant="contained">Save</Button>
363
- <Button variant="contained" onClick={()=>{undoChanges(sensorData.mac_address)}}>Undo</Button>
364
- <Button variant="contained" color="secondary" onClick={(e)=>confirmDelete(sensorData.mac_address)}>Delete</Button>
365
-
366
- </Grid>
367
- </div>
368
- </Form>
369
-
370
- </div>
371
- </div>
439
+ <Tabs
440
+ defaultActiveKey="_configured"
441
+ id="domain-tabs"
442
+ className="mb-3"
443
+ >
444
+ {getTabs()}
445
+ </Tabs>
372
446
  </div>
373
447
  )
374
448