-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsenseair.js
96 lines (79 loc) · 2.29 KB
/
senseair.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import { CronJob } from 'cron'
import Logger from 'logger'
import Client from 'base-client'
import { SerialPort } from 'serialport'
import { PacketLengthParser } from '@serialport/parser-packet-length'
const client = Client({
url: process.env.ARGUS_URL,
apiKey: process.env.ARGUS_API_KEY,
location: process.env.ARGUS_SENSOR_LOCATION,
})
const log = Logger({ name: 'senseair' })
const port = new SerialPort({
path: process.env.SENSEAIR_SERIAL_DEVICE_PATH ?? '/dev/serial0',
baudRate: 9600,
})
const parser = port.pipe(
new PacketLengthParser({
delimiter: 0xfe,
packetOverhead: 5,
lengthBytes: 1,
lengthOffset: 2,
})
)
const STATUS_COMMAND = Buffer.from([
0xfe, 0x04, 0x00, 0x00, 0x00, 0x04, 0xe5, 0xc6,
])
const READ_CO2_COMMAND = Buffer.from([
0xfe, 0x04, 0x00, 0x03, 0x00, 0x01, 0xd5, 0xc5,
])
const latestMeasurement = {
updatedAt: null,
value: null,
}
const onTick = async () => {
log.debug('tick')
const now = new Date()
const minute = 60 * 1000
if (now - latestMeasurement.lastUpdatedAt > 10 * minute) {
log.warn('Measurement is too old, skipping...')
return
}
try {
await client.storeMeasurement({
type: 'co2',
value: latestMeasurement.value,
})
} catch (error) {
log.error(error)
}
}
const measurementJob = CronJob.from({
cronTime: process.env.SENSEAIR_MEASUREMENT_CRON ?? '*/5 * * * *',
onTick,
})
const handleOverflow = (number) => (number > 32768 ? 0 : number)
const start = async () => {
parser.on('data', (data) => {
const length = data[2]
if (length === 2) {
const rawValue = data[3] * 256 + data[4]
const measurementValue = handleOverflow(rawValue)
log.debug(`co2: ${rawValue} ppm`)
latestMeasurement.updatedAt = new Date()
latestMeasurement.value = measurementValue
}
if (length === 8) {
const statusCode = data[4] * 256 + data[5]
const rawValue = data[9] * 256 + data[10]
const measurementValue = handleOverflow(rawValue)
log.info(`sensor status code: ${statusCode}; co2: ${rawValue}ppm`)
latestMeasurement.updatedAt = new Date()
latestMeasurement.value = measurementValue
}
})
setInterval(() => port.write(READ_CO2_COMMAND), 30000)
port.write(STATUS_COMMAND)
measurementJob.start()
}
start().catch((error) => log.error(error))