Skip to content

Commit

Permalink
Add Zizm ZM194-D9Y power meter
Browse files Browse the repository at this point in the history
  • Loading branch information
anataty committed Jul 3, 2023
1 parent 1362318 commit 516cb0f
Show file tree
Hide file tree
Showing 3 changed files with 397 additions and 0 deletions.
14 changes: 14 additions & 0 deletions power_meters/zizm_ZM194-D9Y/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Zizm ZM194-D9Y

This [Enapter Device Blueprint](https://go.enapter.com/marketplace-readme) integrates **Zizm ZM194-D9Y** - 3-Phase Multi-function Power Meter with [ModBus RTU](https://go.enapter.com/developers-enapter-modbus) over [RS-485 communication interface](https://go.enapter.com/developers-enapter-rs485).

## Connect to Enapter

- Sign up to the Enapter Cloud using the [Web](https://cloud.enapter.com/) or mobile app ([iOS](https://apps.apple.com/app/id1388329910), [Android](https://play.google.com/store/apps/details?id=com.enapter&hl=en)).
- Use the [Enapter ENP-RS485](https://go.enapter.com/handbook-enp-rs485) module for physical connection. See [connection instructions](https://go.enapter.com/handbook-enp-rs485-conn) in the module manual.
- [Add ENP-RS485 to your site](https://go.enapter.com/handbook-mobile-app) using the mobile app.
- [Upload](https://go.enapter.com/developers-upload-blueprint) this blueprint to ENP-RS485.
- Use the `Set Up Connection` command in the Enapter mobile or Web app to set up Modbus RTU communication parameters:
- Baudrate;
- Modbus address;
- Parity.
194 changes: 194 additions & 0 deletions power_meters/zizm_ZM194-D9Y/firmware.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
local config = require('enapter.ucm.config')

BAUDRATE = 'baudrate'
ADDRESS = 'address'
PARITY = 'parity'

-- Default RS485 communication interface parameters
DATA_BITS = 8
STOP_BITS = 1

function main()
config.init({
[BAUDRATE] = { type = 'number', required = true, default = 9600 },
[ADDRESS] = { type = 'number', required = true, default = 1 },
[PARITY] = { type = 'string', required = true, default = 'N' },
})

local values, err = config.read_all()
if err then
enapter.log('cannot read config: ' .. tostring(err), 'error')
return nil, 'cannot_read_config'
else
local baudrate, parity = values[BAUDRATE], values[PARITY]

local result = rs485.init(baudrate, DATA_BITS, parity, STOP_BITS)
if result ~= 0 then
enapter.log('RS485 init error: ' .. rs485.err_to_str(result), error, true)
end
end

scheduler.add(30000, send_properties)
scheduler.add(1000, send_telemetry)
end

function send_properties()
enapter.send_properties({
vendor = 'Zizm',
model = 'ZM194-D9Y',
})
end

function send_telemetry()
local telemetry = {}
local status = 'ok'

local all_metrics = {
voltage_a = {
register_address = 0x0000,
register_count = 2,
fn = touint32,
},
voltage_b = {
register_address = 0x0002,
register_count = 2,
fn = touint32,
},
voltage_c = {
register_address = 0x0004,
register_count = 2,
fn = touint32,
},
line_voltage_ab = {
register_address = 0x0006,
register_count = 2,
fn = touint32,
},
line_voltage_bc = {
register_address = 0x0008,
register_count = 2,
fn = touint32,
},
line_voltage_ca = {
register_address = 0x000A,
register_count = 2,
fn = touint32,
},
current_a = {
register_address = 0x000C,
register_count = 2,
fn = touint32,
},
current_b = {
register_address = 0x000E,
register_count = 2,
fn = touint32,
},
current_c = {
register_address = 0x0010,
register_count = 2,
fn = touint32,
},
active_power_a = {
register_address = 0x0012,
register_count = 2,
fn = touint32,
},
active_power_b = {
register_address = 0x0014,
register_count = 2,
fn = touint32,
},
active_power_c = {
register_address = 0x0016,
register_count = 2,
fn = touint32,
},
total_active_power = {
register_address = 0x0018,
register_count = 2,
fn = touint32,
},
reactive_power_a = {
register_address = 0x001A,
register_count = 2,
fn = touint32,
},
reactive_power_b = {
register_address = 0x001C,
register_count = 2,
fn = touint32,
},
reactive_power_c = {
register_address = 0x001E,
register_count = 2,
fn = touint32,
},
total_reactive_power = {
register_address = 0x0020,
register_count = 2,
fn = touint32,
},
frequency = {
register_address = 0x0032,
register_count = 2,
fn = touint32,
},
total_active_electric_energy = {
register_address = 0x0038,
register_count = 2,
fn = touint32,
},
forward_active_electric_energy = {
register_address = 0x003A,
register_count = 2,
fn = touint32,
},
reverse_active_electric_energy = {
register_address = 0x003C,
register_count = 2,
fn = touint32,
},
}

for name, metric in pairs(all_metrics) do
if
not add_to_telemetry(
name,
telemetry,
metric.register_address,
metric.register_count,
metric.fn
)
then
status = 'read_error'
end
end

telemetry['status'] = status
enapter.send_telemetry(telemetry)
end

function add_to_telemetry(metric_name, tbl, register_address, registers_count, fn)
local address, err = config.read(ADDRESS)
if err == nil then
local data, result = modbus.read_holdings(address, register_address, registers_count, 1000)
if data then
tbl[metric_name] = fn(data) / 1000.0 -- coefficient 0.001 for all metrics
return true
else
enapter.log(
'Register ' .. register_address .. ' reading failed: ' .. modbus.err_to_str(result)
)
end
end
return false
end

function touint32(register)
local raw_str =
string.pack('BBBB', register[1] >> 8, register[1] & 0xff, register[2] >> 8, register[2] & 0xff)
return string.unpack('>I2', raw_str)
end

main()
189 changes: 189 additions & 0 deletions power_meters/zizm_ZM194-D9Y/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
blueprint_spec: device/1.0
display_name: Zizm ZM194-D9Y
description: 3-Phase Multi-function Power Meter.
icon: enapter-power-meter
vendor: zizm
author: enapter
support:
url: https://go.enapter.com/enapter-blueprint-support
email: [email protected]
license: MIT
verification_level: verified

communication_module:
product: ENP-RS485
lua:
file: firmware.lua
dependencies:
- enapter-ucm

properties:
vendor:
type: string
display_name: Vendor
model:
type: string
display_name: Model

telemetry:
status:
display_name: Modbus status
type: string
enum:
- ok
- read_error
total_active_power:
type: float
unit: kwatt
display_name: Total Active Power
total_active_electric_energy:
type: float
unit: kwatth
display_name: Total Active Electric Energy
active_power_a:
type: float
unit: kwatt
display_name: Active Power A
active_power_b:
type: float
unit: watt
display_name: Active Power B
active_power_c:
type: float
unit: kwatt
display_name: Active Power C
voltage_a:
type: float
unit: volt
display_name: Phase A Voltage
voltage_b:
type: float
unit: volt
display_name: Phase B Voltage
voltage_c:
type: float
unit: volt
display_name: Phase C Voltage
line_voltage_ab:
type: float
unit: volt
display_name: Line Voltage AB
line_voltage_bc:
type: float
unit: volt
display_name: Line Voltage BC
line_voltage_ca:
type: float
unit: volt
display_name: Line Voltage CA
current_a:
type: float
unit: amp
display_name: Phase A Current
current_b:
type: float
unit: amp
display_name: Phase B Current
current_c:
type: float
unit: amp
display_name: Phase C Current
frequency:
type: float
unit: hertz
display_name: Frequency
total_reactive_power:
type: float
unit: watt
display_name: Total Reactive Power
reactive_power_a:
type: float
unit: watt
display_name: Reactive Power A
reactive_power_b:
type: float
unit: watt
display_name: Reactive Power B
reactive_power_c:
type: float
unit: watt
display_name: Reactive Power C
forward_active_electric_energy:
type: float
unit: kwatth
display_name: Forward Active Electric Energy
reverse_active_electric_energy:
type: float
unit: kwatth
display_name: Reverse Active Electric Energy

command_groups:
connection:
display_name: Connection

commands:
# TODO: mark commands containing secrets
write_configuration:
display_name: Set Up Connection
description: Set Modbus RTU connection
group: connection
populate_values_command: read_configuration
ui:
icon: file-document-edit-outline
arguments:
baudrate:
display_name: Baudrate
type: integer
required: true
enum:
- 2400
- 4800
- 9600
address:
display_name: Modbus address
type: integer
required: true
min: 1
max: 247
parity:
display_name: Parity
type: string
required: true
enum:
- N
- E
- O
read_configuration:
display_name: Read Connection Parameters
group: connection
ui:
icon: file-check-outline
.cloud:
category: power_meters
mobile_main_chart: total_active_power
mobile_telemetry:
- total_active_electric_energy
- total_active_power
- active_power_a
- active_power_b
- active_power_c
- voltage_a
- voltage_b
- voltage_c
- current_a
- current_b
- current_c
- frequency
mobile_charts:
- total_active_electric_energy
- total_active_power
- active_power_a
- active_power_b
- active_power_c
- voltage_a
- voltage_b
- voltage_c
- current_a
- current_b
- current_c
- frequency

0 comments on commit 516cb0f

Please sign in to comment.