Browse Source

:recycle: linking controllers to channels to readers | passing callbacks for onRead and onUpdate

master
j 2 years ago
parent
commit
5848ab259e
7 changed files with 202 additions and 23 deletions
  1. 0
    0
      src/actions.js
  2. 64
    0
      src/channel.js
  3. 39
    0
      src/controller.js
  4. 12
    4
      src/index.js
  5. 39
    8
      src/system.js
  6. 8
    1
      src/utils.js
  7. 40
    10
      test/system.spec.js

+ 0
- 0
src/actions.js View File


+ 64
- 0
src/channel.js View File

@@ -0,0 +1,64 @@
1
+/**
2
+ * @type {Reading}
3
+ */
4
+class Reading {
5
+    constructor({ onRead, unit, min, max }) {
6
+        this._val = onRead
7
+        this.unit = unit
8
+        this.max = max
9
+        this.min = min
10
+        this.created = Date.now()
11
+    }
12
+    /**
13
+     * Reach out and grabs the value
14
+     * from some sensor
15
+     */
16
+    get val() {
17
+        return this._val()
18
+    }
19
+}
20
+
21
+/**
22
+ * @type {Channel}
23
+ */
24
+class Channel {
25
+    constructor({ interval = 1, reader = null }) {
26
+        this._interval = interval
27
+        this._reader = reader
28
+    }
29
+    get interval() {
30
+        return this._interval
31
+    }
32
+    get val() {
33
+        return this._reader.val
34
+    }
35
+    get unit() {
36
+        return this._reader.unit
37
+    }
38
+    get aboveRange() {
39
+        return this._reader.val > this._reader.max
40
+    }
41
+    get belowRange() {
42
+        return this._reader.val < this._reader.min
43
+    }
44
+    get inRange() {
45
+        return this._reader.val && !this.aboveRange && !this.belowRange
46
+            ? true
47
+            : false
48
+    }
49
+    /** Always return a new Reading instance with new Channel instances */
50
+    update() {
51
+        const reader = new Reading({
52
+            // !: Setup the callback to return a sensor value
53
+            onRead: this._reader._val,
54
+            unit: this._reader.unit,
55
+            max: this._reader.max,
56
+            min: this._reader.min,
57
+        })
58
+
59
+        const chan = new Channel({ interval: this.interval, reader })
60
+        return chan
61
+    }
62
+}
63
+
64
+export { Channel, Reading }

+ 39
- 0
src/controller.js View File

@@ -0,0 +1,39 @@
1
+let allWarnings = []
2
+
3
+// const _makeWarning = (msg, channelOrSensor) => ({
4
+//     created: Date.now(),
5
+//     warning: `[warning]: ${msg}`,
6
+//     channelOrSensor,
7
+// })
8
+
9
+const controllerTypes = {
10
+    temp: 'temperature',
11
+    level: 'water_level',
12
+}
13
+
14
+/**
15
+ * Object to link a channel to an action
16
+ *
17
+ * @type {Controller} links together channels
18
+ **/
19
+class Controller {
20
+    constructor({ type, channel }) {
21
+        this._type = type
22
+        this.channel = channel
23
+    }
24
+    get type() {
25
+        return this._type
26
+    }
27
+    get inRange() {
28
+        return this.channel.inRange
29
+    }
30
+    update() {
31
+        this.channel = this.channel.update()
32
+        return this.channel.val
33
+    }
34
+    onUpdate() {
35
+        // Not implemented here
36
+    }
37
+}
38
+
39
+export { Controller, controllerTypes }

+ 12
- 4
src/index.js View File

@@ -4,10 +4,18 @@ import loop from './loop.js'
4 4
 import { System, makeContainerT } from './system.js'
5 5
 import { Container } from './container.js'
6 6
 
7
+class InputConf {
8
+    constructor(type, onRead, readInterval, onUpdate) {
9
+        ;(this.type = type),
10
+            (this.onRead = onRead),
11
+            (this.interval = readInterval),
12
+            (this.onUpdate = onUpdate)
13
+    }
14
+}
7 15
 const fromConfig = {
8 16
     tank_1: {
9
-        inputs: [1],
10
-        outputs: ['foo'],
17
+        inputs: [],
18
+        outputs: [],
11 19
         dims: { l: 24, w: 12, h: 12 },
12 20
     },
13 21
     sump_1: {
@@ -36,8 +44,6 @@ const digestConfig = config => {
36 44
 }
37 45
 
38 46
 /** Holds systems or containers */
39
-class Controller {}
40
-
41 47
 const mySystem = digestConfig(fromConfig)
42 48
 
43 49
 // Start the loop!
@@ -61,3 +67,5 @@ setTimeout(function () {
61 67
     console.log('6000ms passed, stopping the game loop')
62 68
     loop.active.splice(loop.active.indexOf(0), 1)
63 69
 }, 6000)
70
+
71
+export { InputConf }

+ 39
- 8
src/system.js View File

@@ -1,13 +1,20 @@
1
-/** Holds systems or containers */
1
+import { Reading, Channel } from './channel'
2
+import { Controller } from './controller'
3
+
4
+/**
5
+ * Object that holds each container and their input and outputs
6
+ *
7
+ * @type {System}
8
+ */
2 9
 class System {
3 10
     constructor() {
4 11
         this.inventory = {}
5 12
     }
6 13
     get inputs() {
7
-        return Object.values(this.inventory).map(containerT => containerT[0])
14
+        return Object.values(this.inventory).map(containerT => containerT[0][0])
8 15
     }
9 16
     get outputs() {
10
-        return Object.values(this.inventory).map(containerT => containerT[1])
17
+        return Object.values(this.inventory).map(containerT => containerT[1][0])
11 18
     }
12 19
     get containers() {
13 20
         return Object.values(this.inventory).map(containerT => containerT[2])
@@ -38,10 +45,34 @@ class System {
38 45
     }
39 46
 }
40 47
 
41
-const makeContainerT = (inputs, outputs, container) => [
42
-    inputs,
43
-    outputs,
44
-    container,
45
-]
48
+/**
49
+ * Take in inputConf objects (see: index.js)
50
+ * and returns Controllers with an initial reading
51
+ **/
52
+const _makeControllerFromInputConfig = ({
53
+    type,
54
+    onRead,
55
+    interval,
56
+    onUpdate,
57
+}) => {
58
+    const reader = new Reading({
59
+        onRead,
60
+        unit: 'F',
61
+        max: 80,
62
+        min: 72,
63
+    })
64
+
65
+    const controller = new Controller({
66
+        type,
67
+        channel: new Channel({ interval, reader }),
68
+    })
69
+    controller.onUpdate = onUpdate
70
+    return controller
71
+}
72
+
73
+const makeContainerT = (inputs, outputs, container) => {
74
+    const controllers = inputs.map(_makeControllerFromInputConfig)
75
+    return [controllers, outputs, container]
76
+}
46 77
 
47 78
 export { System, makeContainerT }

+ 8
- 1
src/utils.js View File

@@ -27,4 +27,11 @@ const _changeLevel = (amount, container) => {
27 27
 const fill = ({ container, amount }) => _changeLevel(amount, container)
28 28
 const drain = ({ container, amount }) => _changeLevel(-1 * amount, container)
29 29
 
30
-export { toLiquid, fromLiquid, fill, drain }
30
+const interpolate = ({ x, y, from }) => {
31
+    const [x1, x2] = x
32
+    const [y1, y2] = y
33
+    const to = y1 + ((y2 - y1) / (x2 - x1)) * (from - x1)
34
+    return to
35
+}
36
+
37
+export { toLiquid, fromLiquid, fill, drain, interpolate }

+ 40
- 10
test/system.spec.js View File

@@ -1,25 +1,55 @@
1 1
 import { expect, test } from 'vitest'
2
-import { System } from '../src/system.js'
2
+import { System, makeContainerT } from '../src/system.js'
3
+import { Reading } from '../src/channel.js'
4
+import { Container } from '../src/container.js'
5
+import { controllerTypes } from '../src/controller.js'
6
+import { InputConf } from '../src/index.js'
3 7
 
4 8
 test('system - instantiates and stores inventory correctly', () => {
5 9
     let testSystem = new System()
6
-    testSystem.add('aaa', ['input_test', 'output_test', { id: 'aaa' }])
7
-    expect(testSystem.inputs).toStrictEqual(['input_test'])
8
-    expect(testSystem.outputs).toStrictEqual(['output_test'])
9
-    expect(testSystem.containers[0].id).toStrictEqual('aaa')
10
-
11
-    // Make sure inputs and outputs get reassigned
12
-    testSystem.replaceContainer({ id: 'aaa' })
10
+    testSystem.add('aaa', [['input_test'], ['output_test'], { id: 'aaa' }])
13 11
     expect(testSystem.inputs).toStrictEqual(['input_test'])
14 12
     expect(testSystem.outputs).toStrictEqual(['output_test'])
15 13
     expect(testSystem.containers[0].id).toStrictEqual('aaa')
16 14
 
17 15
     const inputs = testSystem.inputsFor({ id: 'aaa' })
18
-    expect(inputs).toStrictEqual('input_test')
16
+    expect(inputs).toStrictEqual(['input_test'])
19 17
 
20 18
     const outputs = testSystem.outputsFor({ id: 'aaa' })
21
-    expect(outputs).toStrictEqual('output_test')
19
+    expect(outputs).toStrictEqual(['output_test'])
22 20
 
23 21
     testSystem.remove('aaa')
24 22
     expect(testSystem.inventory).toStrictEqual({})
25 23
 })
24
+
25
+test('system - instiantes channels with readers correctly', () => {
26
+    let testSystem = new System()
27
+    let testContainer = new Container({ l: 10, w: 10, h: 10 })
28
+    let mockTemp = 70
29
+    let testInConf = new InputConf(
30
+        controllerTypes.temp,
31
+        () => mockTemp,
32
+        0.1,
33
+        () => {
34
+            console.log('tick')
35
+            return 'tick'
36
+        }
37
+    )
38
+    const cT = makeContainerT([testInConf], [], testContainer)
39
+    testSystem.add('aaa', cT)
40
+
41
+    expect(testSystem.inputs[0].type).toStrictEqual('temperature')
42
+
43
+    let chan = testSystem.inputs[0].channel
44
+    expect(chan.interval).toStrictEqual(0.1)
45
+
46
+    // Test that the channel and channel.reader are working
47
+    expect(chan.val).toStrictEqual(70)
48
+    expect(chan.unit).toStrictEqual('F')
49
+    expect(chan.inRange).toStrictEqual(false)
50
+    expect(testSystem.inputs[0].onUpdate()).toStrictEqual('tick')
51
+
52
+    mockTemp = 79
53
+    chan = chan.update()
54
+    expect(chan.val).toStrictEqual(79)
55
+})

Loading…
Cancel
Save