Skip to content

Commit

Permalink
Add very basic Modbus sensor support
Browse files Browse the repository at this point in the history
Closes #55
  • Loading branch information
Jalle19 committed May 7, 2024
1 parent 7c7cc82 commit 12c3d29
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 3 deletions.
241 changes: 241 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"dependencies": {
"@influxdata/influxdb-client": "^1.33.2",
"axios": "^1.6.0",
"modbus-serial": "^8.0.16",
"mqtt": "^5.1.2",
"slugify": "^1.6.6",
"winston": "^3.11.0",
Expand Down
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getCharacteristicsSensorData as getIotawattCharacteristicsSensorData,
getSensorData as getIotawattSensorData,
} from './sensor/iotawatt'
import { getSensorData as getModbusSensorData } from './sensor/modbus'
import { getSensorData as getVirtualSensorData } from './sensor/virtual'
import { getSensorData as getUnmeteredSensorData } from './sensor/unmetered'
import {
Expand Down Expand Up @@ -153,6 +154,9 @@ export const resolveAndValidateConfig = (config: Config): Config => {
case SensorType.Iotawatt:
circuit.sensor.pollFunc = getIotawattSensorData
break
case SensorType.Modbus:
circuit.sensor.pollFunc = getModbusSensorData
break
case SensorType.Virtual:
circuit.sensor.pollFunc = getVirtualSensorData
break
Expand Down
9 changes: 6 additions & 3 deletions src/eachwatt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { WebSocketPublisherImpl } from './publisher/websocket'
import { PublisherType } from './publisher'
import { pollCharacteristicsSensors } from './characteristics'
import { createLogger } from './logger'
import { setRequestTimeout } from './http/client'
import { setRequestTimeout as setHttpRequestTimeout } from './http/client'
import { setRequestTimeout as setModbusRequestTimeout } from './modbus/client'

// Set up a signal handler, so we can exit on Ctrl + C when run from Docker
process.on('SIGINT', () => {
Expand Down Expand Up @@ -101,10 +102,12 @@ const mainPollerFunc = async (config: Config) => {
publisherImpl: webSocketServer,
})

// Adjust the HTTP timeout to be half that of the polling interval
// Adjust request timeouts to be half that of the polling interval
const pollingInterval = config.settings.pollingInterval
logger.info(`Polling sensors with interval ${pollingInterval} milliseconds`)
setRequestTimeout((pollingInterval as number) / 2)
const timeoutMs = (pollingInterval as number) / 2
setHttpRequestTimeout(timeoutMs)
setModbusRequestTimeout(timeoutMs)

// Start polling sensors
await mainPollerFunc(config)
Expand Down
24 changes: 24 additions & 0 deletions src/modbus/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createLogger } from '../logger'
import ModbusRTU from 'modbus-serial'

const logger = createLogger('modbus')

// Request timeout configuration
export let requestTimeout = 5000

export const setRequestTimeout = (timeoutMs: number) => {
requestTimeout = timeoutMs
logger.info(`Using ${timeoutMs} millisecond timeout for Modbus operations`)
}

// Keep track of clients, use one per address
const clients = new Map<string, ModbusRTU>()

export const getClient = (address: string): ModbusRTU => {
if (!clients.has(address)) {
const client = new ModbusRTU()
clients.set(address, client)
}

return clients.get(address) as ModbusRTU
}
14 changes: 14 additions & 0 deletions src/sensor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Characteristics } from './characteristics'
export enum SensorType {
Iotawatt = 'iotawatt',
Shelly = 'shelly',
Modbus = 'modbus',
Virtual = 'virtual',
Unmetered = 'unmetered',
Dummy = 'dummy',
Expand Down Expand Up @@ -76,6 +77,19 @@ export interface IotawattSensor extends PowerSensor {
iotawatt: IotawattSensorSettings
}

export interface ModbusSensorSettings {
address: string
port: number
unit: number
register: number
type: 'int16'
}

export interface ModbusSensor extends PowerSensor {
type: SensorType.Modbus
modbus: ModbusSensorSettings
}

interface VirtualSensorSettings {
children: (string | Circuit)[] // resolved to circuit at runtime
}
Expand Down
Loading

0 comments on commit 12c3d29

Please sign in to comment.