diff --git a/.categories/motor_controllers.svg b/.categories/motor_controllers.svg new file mode 100644 index 00000000..f0479e7b --- /dev/null +++ b/.categories/motor_controllers.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/.marketplace/devices/devices.yml b/.marketplace/devices/devices.yml index cb2177bf..d97ee5bd 100644 --- a/.marketplace/devices/devices.yml +++ b/.marketplace/devices/devices.yml @@ -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-motor-controller + 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. diff --git a/.marketplace/vendors/icons/kostal.png b/.marketplace/vendors/icons/kostal.png new file mode 100644 index 00000000..c0699ac2 Binary files /dev/null and b/.marketplace/vendors/icons/kostal.png differ diff --git a/.marketplace/vendors/vendors.yml b/.marketplace/vendors/vendors.yml index c8956925..a92c294d 100644 --- a/.marketplace/vendors/vendors.yml +++ b/.marketplace/vendors/vendors.yml @@ -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 diff --git a/motor_controllers/kostal_inveor/README.md b/motor_controllers/kostal_inveor/README.md new file mode 100644 index 00000000..e3c9108e --- /dev/null +++ b/motor_controllers/kostal_inveor/README.md @@ -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. + +## 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) diff --git a/motor_controllers/kostal_inveor/firmware.lua b/motor_controllers/kostal_inveor/firmware.lua new file mode 100644 index 00000000..1543efa0 --- /dev/null +++ b/motor_controllers/kostal_inveor/firmware.lua @@ -0,0 +1,115 @@ +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' + +function main() + 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] + local stop_bits = values[STOP_BITS_CONFIG] + + local result = rs485.init(baudrate, data_bits, parity_bits, stop_bits) + if result ~= 0 then + enapter.log('RS485 init 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() + 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, 1999, 2, 1000) -- REAL + if data then + telemetry['actual_freq'] = tofloat(data) + else + enapter.log('Register 1999 reading failed: ' .. modbus.err_to_str(result)) + status = 'read_error' + end + + local data, result = modbus.read_inputs(address, 2001, 2, 1000) -- REAL + if data then + telemetry['output_volt'] = tofloat(data) + else + enapter.log('Register 2001 reading failed: ' .. modbus.err_to_str(result)) + status = 'read_error' + end + + local data, result = modbus.read_inputs(address, 2003, 2, 1000) -- REAL + if data then + telemetry['motor_curr'] = tofloat(data) * telemetry['volt_l1n'] + else + enapter.log('Register 2003 reading failed: ' .. modbus.err_to_str(result)) + status = 'read_error' + end + + local data, result = modbus.read_inputs(address, 2009, 2, 1000) -- REAL + if data then + telemetry['target_freq'] = tofloat(data) + else + enapter.log('Register 2009 reading failed: ' .. modbus.err_to_str(result)) + status = 'read_error' + end + + local data, result = modbus.read_inputs(address, 2015, 2, 1000) -- REAL + if data then + telemetry['inner_temp'] = tofloat(data) + else + enapter.log('Register 2015 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() diff --git a/motor_controllers/kostal_inveor/manifest.yml b/motor_controllers/kostal_inveor/manifest.yml new file mode 100644 index 00000000..8cce0c03 --- /dev/null +++ b/motor_controllers/kostal_inveor/manifest.yml @@ -0,0 +1,124 @@ +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 ~> 0.3.2-1 + +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 + 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 + type: integer + min: 1 + max: 247 + required: true + baudrate: + display_name: Baudrate + type: integer + required: true + enum: + - 9600 + - 19200 + - 38400 + - 57600 + - 115200 + - 2400 + - 4800 + data_bits: + display_name: Data bits + type: integer + required: true + enum: + - 8 + parity_bits: + display_name: None + type: string + enum: + - N + - O + - E + required: true + stop_bits: + display_name: Stop bits + type: integer + required: true + enum: + - 1 + - 2 + read_configuration: + display_name: Read Configuration + group: config + ui: + icon: wrench-outline + +.cloud: + category: power_meters + mobile_telemetry: + - target_freq + - actual_freq + - output_volt + - motor_curr + - inner_temp