Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add KOSTAL INVEOR #244

Merged
merged 21 commits into from
Oct 18, 2023
6 changes: 6 additions & 0 deletions .categories/motor_controllers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions .marketplace/devices/devices.yml
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,16 @@
- blueprint: hvac/vitobloc
verification_level: ready_for_testing

- id: inveor
display_name: KOSTAL INVEOR MP/MP Modular/MPP/M
description: Variable frequency drive.
icon: enapter-power-meter
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
vendor: kostal
category: motor_controllers
blueprint_options:
- blueprint: motor_controllers/kostal_inveor
verification_level: ready_for_testing

- id: igd_toc_635
display_name: IGD TOC 635
description: Addressable gas-detector control panel.
Expand Down
Binary file added .marketplace/vendors/icons/kostal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions .marketplace/vendors/vendors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@
icon_url: https://raw.githubusercontent.com/Enapter/marketplace/main/.marketplace/vendors/icons/viessmann.png
website: https://www.viessmann.family/

- id: kostal
display_name: KOSTAL
icon_url: https://raw.githubusercontent.com/Enapter/marketplace/main/.marketplace/vendors/icons/kostal.png
website: https://www.kostal.com/

- id: igd
display_name: International Gas Detectors Ltd
icon_url: https://raw.githubusercontent.com/Enapter/marketplace/main/.marketplace/vendors/icons/igd.png
Expand Down
15 changes: 15 additions & 0 deletions motor_controllers/kostal_inveor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# KOSTAL INVEOR MP/MP Modular/MPP/M

This [Enapter Device Blueprint](https://go.enapter.com/marketplace-readme) integrates **KOSTAL INVEOR** - variable frequency drives 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.
anataty marked this conversation as resolved.
Show resolved Hide resolved

## References

- [KOSTAL INVEOR Products Page](https://go.enapter.com/kostal_inveor_products_page)
- [KOSTAL INVEOR Modbus Manual](https://go.enapter.com/kostal_inveor_modbus_manual)
126 changes: 126 additions & 0 deletions motor_controllers/kostal_inveor/firmware.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
local config = require('enapter.ucm.config')

ADDRESS_CONFIG = 'address'
BAUDRATE_CONFIG = 'baudrate'
DATA_BITS_CONFIG = 'data_bits'
STOP_BITS_CONFIG = 'stop_bits'
PARITY_CONFIG = 'parity_bits'
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved

function main()
enapter.log('DEBUG MAIN')
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved

config.init({
[ADDRESS_CONFIG] = { type = 'number', required = true, default = 1 },
[BAUDRATE_CONFIG] = { type = 'number', required = true, default = 9600 },
[DATA_BITS_CONFIG] = { type = 'number', required = true, default = 8 },
[STOP_BITS_CONFIG] = { type = 'number', required = true, default = 1 },
[PARITY_CONFIG] = { 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
for _, value in pairs(values) do
if not value then
return nil, 'not_configured'
end
end
end

local baudrate = values[BAUDRATE_CONFIG]
local data_bits = values[DATA_BITS_CONFIG]
local parity_bits = values[PARITY_CONFIG]
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
local stop_bits = values[STOP_BITS_CONFIG]

local result = rs485.init(baudrate, data_bits, parity_bits, stop_bits)
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
if result ~= 0 then
enapter.log('RS-485 failed: ' .. result .. ' ' .. rs485.err_to_str(result), 'error', true)
end

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

function send_properties()
enapter.send_properties({ vendor = 'KOSTAL', model = 'INVEOR' })
end

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

local values, err = config.read_all()
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
if err then
enapter.log('cannot read config: ' .. tostring(err), 'error')
return nil, 'cannot_read_config'
else
for _, value in pairs(values) do
if not value then
return nil, 'not_configured'
end
end
end

local address = values[ADDRESS_CONFIG]

local data, result = modbus.read_inputs(address, 999, 1, 1000)
if data then
telemetry['actual_freq'] = tofloat(data)
anataty marked this conversation as resolved.
Show resolved Hide resolved
else
enapter.log('Register 999 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

local data, result = modbus.read_inputs(address, 1000, 1, 1000)
if data then
telemetry['output_volt'] = tofloat(data)
else
enapter.log('Register 1000 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

local data, result = modbus.read_inputs(address, 1001, 1, 1000)
if data then
telemetry['motor_curr'] = tofloat(data) * telemetry['volt_l1n']
else
enapter.log('Register 1001 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

local data, result = modbus.read_inputs(address, 1007, 1, 1000)
if data then
telemetry['igbt_temp'] = tofloat(data)
else
enapter.log('Register 1007 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

local data, result = modbus.read_inputs(address, 1004, 1, 1000)
if data then
telemetry['target_freq'] = tofloat(data)
else
enapter.log('Register 1004 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

local data, result = modbus.read_inputs(address, 1002, 1, 1000)
if data then
telemetry['inner_temp'] = tofloat(data)
else
enapter.log('Register 1002 reading failed: ' .. modbus.err_to_str(result))
status = 'read_error'
end

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

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

main()
114 changes: 114 additions & 0 deletions motor_controllers/kostal_inveor/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
blueprint_spec: device/1.0

display_name: KOSTAL INVEOR
description: Variable frequency drive and motor controller
icon: enapter-motor-controller
vendor: kostal
author: enapter
contributors:
- anataty
- alexandershalin
support:
url: https://go.enapter.com/enapter-blueprint-support
email: support@enapter.com
license: MIT
verification_level: ready_for_testing

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- enapter-ucm
- enapter-ucm ~> 0.3.2-1

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean?


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

telemetry:
status:
display_name: Status
type: string
enum:
- ok
- read_error
target_freq:
type: float
unit: Hz
display_name: Target Frequency
actual_freq:
type: float
unit: Hz
display_name: Actual Frequency
output_volt:
type: float
unit: V
display_name: Output Voltage
motor_curr:
type: float
unit: A
display_name: Motor Current
igbt_temp:
type: float
unit: °C
display_name: IGBT Temperature
inner_temp:
type: float
unit: °C
display_name: Inner Temperature

command_groups:
config:
display_name: Configuration
commands:
write_configuration:
populate_values_command: read_configuration
display_name: Configure
group: config
ui:
icon: wrench-outline
arguments:
address:
display_name: Modbus address
description: 1-247
anataty marked this conversation as resolved.
Show resolved Hide resolved
type: integer
required: true
baudrate:
display_name: Baudrate
type: integer
required: true
data_bits:
display_name: Data bits
type: integer
required: true
parity_bits:
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
display_name: None
type: string
enum:
- N
- O
- E
required: true
stop_bits:
anataty marked this conversation as resolved.
Show resolved Hide resolved
display_name: Stop bits
type: integer
required: true
read_configuration:
display_name: Read Configuration
group: config
ui:
icon: wrench-outline

.cloud:
category: power_meters
alexandershalin marked this conversation as resolved.
Show resolved Hide resolved
mobile_telemetry:
- target_freq
- actual_freq
- output_volt
- motor_curr
- igbt_temp
- inner_temp
Loading