bt-sensors-plugin-sk 1.2.0-beta.0.0.9 → 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,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')
@@ -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
- console.log("getSensorData")
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
99
  console.log("getBaseData")
89
- const response = await fetchJSONData("base")
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
  }
@@ -96,7 +107,7 @@ export default (props) => {
96
107
  }
97
108
  async function getProgress(){
98
109
  console.log("getProgress")
99
- const response = await fetchJSONData("progress")
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
  }
@@ -107,7 +118,7 @@ export default (props) => {
107
118
 
108
119
  function updateSensorData(data){
109
120
  console.log("updateSensorData")
110
- sendJSONData("sendSensorData", data).then((response)=>{
121
+ sendJSONData("updateSensorData", data).then((response)=>{
111
122
  if (response.status != 200) {
112
123
  throw new Error(response.statusText)
113
124
  }
@@ -148,7 +159,7 @@ export default (props) => {
148
159
  function updateBaseData(data){
149
160
  console.log("updateBaseData")
150
161
 
151
- sendJSONData("sendBaseData", data).then( (response )=>{
162
+ sendJSONData("updateBaseData", data).then( (response )=>{
152
163
  if (response.status != 200) {
153
164
  setError(new Error(`Unable to update base data: ${response.statusText} (${response.status})`))
154
165
  } else {
@@ -166,7 +177,7 @@ export default (props) => {
166
177
  function refreshSensors(){
167
178
  console.log('refreshing sensor map')
168
179
 
169
- getSensorData().then((sensors)=>{
180
+ getSensors().then((sensors)=>{
170
181
  setSensorMap (new Map(sensors.map((sensor)=>[sensor.info.mac,sensor])));
171
182
  })
172
183
  .catch((e)=>{
@@ -177,9 +188,17 @@ export default (props) => {
177
188
 
178
189
  useEffect(()=>{
179
190
  console.log("useEffect([])")
180
- fetchJSONData("sendPluginState").then( async (response)=> {
191
+ fetchJSONData("getPluginState").then( async (response)=> {
192
+ if (response.status==404) {
193
+ setPluginState("unknown")
194
+ throw new Error("unable to get plugin state")
195
+ }
181
196
  const json = await response.json()
182
197
  setPluginState(json.state)
198
+
199
+
200
+ _sensorDomains = await getDomains()
201
+
183
202
  console.log("Setting up eventsource")
184
203
  const eventSource = new EventSource("/plugins/bt-sensors-plugin-sk/sse")
185
204
 
@@ -251,10 +270,7 @@ useEffect(()=>{
251
270
 
252
271
  },[pluginState])
253
272
 
254
- useEffect(()=>{
255
- console.log("useEffect([error])")
256
- console.log(error)
257
- },[error])
273
+
258
274
 
259
275
  function confirmDelete(mac){
260
276
  const result = window.confirm(`Delete configuration for ${mac}?`)
@@ -281,29 +297,21 @@ function signalStrengthIcon(sensor){
281
297
  return <SignalCellular0Bar/>
282
298
 
283
299
  }
284
- useEffect(()=>{
285
- console.log("useEffect([sensorMap])")
300
+ function hasConfig(sensor){
301
+ return Object.keys(sensor.config).length>0;
302
+ }
286
303
 
287
- _sensorMap = sensorMap
288
-
289
- setSensorList(
290
-
291
- Array.from(sensorMap.entries()).map((entry) => {
292
- const sensor = sensorMap.get(entry[0]);
293
- const config= sensor.config
294
- const hasConfig = Object.keys(config).length>0;
295
-
296
-
297
- return <ListGroupItem action
304
+ function createListGroupItem(sensor){
305
+
306
+ const config = hasConfig(sensor)
307
+ return <ListGroupItem action
298
308
  onClick={()=>{
299
- if (sensor){
300
- config.mac_address=entry[0]
309
+ sensor.config.mac_address=sensor.info.mac
301
310
  setSchema(sensor.schema)
302
- setSensorData(config)
303
- }
311
+ setSensorData(sensor.config)
304
312
  }
305
313
  }>
306
- <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"}}>
307
315
  {`${sensor._changesMade?"*":""}${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
308
316
  <div class="d-flex justify-content-between ">
309
317
  {
@@ -312,9 +320,37 @@ useEffect(()=>{
312
320
  </div>
313
321
  </div>
314
322
  </ListGroupItem>
315
- })
316
- )
317
-
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
+
318
354
  },[sensorMap]
319
355
  )
320
356
 
@@ -322,18 +358,71 @@ useEffect(()=>{
322
358
  return value==null? NaN : value
323
359
  }
324
360
 
325
-
326
- if (pluginState=="stopped")
327
- 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>)
328
416
  else
329
417
  return(
418
+
330
419
  <div>
331
- {error?<h2 style="color: red;">{error.message}</h2>:""}
420
+ {error?<h2 style="color: red;">{error}</h2>:""}
332
421
  <Form
333
422
  schema={baseSchema}
334
423
  validator={validator}
335
424
  onChange={(e) => setBaseData(e.formData)}
336
- onSubmit={ ({ formData }, e) => {setSensorData(null); updateBaseData(formData) }}
425
+ onSubmit={ ({ formData }, e) => { updateBaseData(formData); setSchema({}) } }
337
426
  onError={log('errors')}
338
427
  formData={baseData}
339
428
  />
@@ -344,46 +433,16 @@ useEffect(()=>{
344
433
  now={progress.progress}
345
434
  />:""
346
435
  }
347
- <h2>{`${sensorMap.size>0?"Bluetooth Devices click to configure" :""}`}</h2>
348
- <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>
349
438
  <p></p>
350
- <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
351
- <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
352
- {sensorList}
353
- </ListGroup>
354
- <div style= {{ paddingLeft: 10, paddingTop: 10, display: (Object.keys(schema).length==0)? "none" :"" }} >
355
- <Form
356
- schema={schema}
357
- validator={validator}
358
- uiSchema={uiSchema}
359
- onChange={(e) => {
360
- const s = sensorMap.get(e.formData.mac_address)
361
- s._changesMade=true
362
- //s.config = e.formData;
363
-
364
- setSensorData(e.formData)
365
- }
366
- }
367
- onSubmit={({ formData }, e) => {
368
- console.log(formData)
369
- updateSensorData(formData)
370
- setSchema({})
371
- alert("Changes saved")
372
- }}
373
- onError={log('errors')}
374
- formData={sensorData}>
375
- <div>
376
- <Grid direction="row" style={{spacing:5}}>
377
- <Button type='submit' color="primary" variant="contained">Save</Button>
378
- <Button variant="contained" onClick={()=>{undoChanges(sensorData.mac_address)}}>Undo</Button>
379
- <Button variant="contained" color="secondary" onClick={(e)=>confirmDelete(sensorData.mac_address)}>Delete</Button>
380
-
381
- </Grid>
382
- </div>
383
- </Form>
384
-
385
- </div>
386
- </div>
439
+ <Tabs
440
+ defaultActiveKey="_configured"
441
+ id="domain-tabs"
442
+ className="mb-3"
443
+ >
444
+ {getTabs()}
445
+ </Tabs>
387
446
  </div>
388
447
  )
389
448