Skip to content

Commit

Permalink
[modbus.sbc] Initial contribution (#9174)
Browse files Browse the repository at this point in the history
Signed-off-by: Fabian Wolter <github@fabian-wolter.de>
  • Loading branch information
fwolter authored Feb 2, 2021
1 parent ff3ff93 commit 0be7f60
Show file tree
Hide file tree
Showing 14 changed files with 518 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
/bundles/org.openhab.binding.modbus/ @ssalonen
/bundles/org.openhab.binding.modbus.e3dc/ @weymann
/bundles/org.openhab.binding.modbus.helioseasycontrols/ @bern77
/bundles/org.openhab.binding.modbus.sbc/ @fwolter
/bundles/org.openhab.binding.modbus.stiebeleltron/ @pail23
/bundles/org.openhab.binding.modbus.studer/ @giovannimirulla
/bundles/org.openhab.binding.modbus.sunspec/ @mrbig
Expand Down
5 changes: 5 additions & 0 deletions bom/openhab-addons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,11 @@
<artifactId>org.openhab.binding.modbus.helioseasycontrols</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus.sbc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus.stiebeleltron</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions bundles/org.openhab.binding.modbus.sbc/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.

* Project home: https://www.openhab.org

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/openhab/openhab-addons
74 changes: 74 additions & 0 deletions bundles/org.openhab.binding.modbus.sbc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Modbus Saia Burgess Controls Binding

This binding interfaces the energy meter series ALD1 by Saia Burgess Controls (SBC) via Modbus.

## Supported Things

The following Things are supported:

- `ald1Unidirectional`: 1-phase 32A one-way energy meter ALD1D5FD00A3A00
- `ald1Bidirectional`: 1-phase 32A two-way energy meter ALD1B5FD00A3A00

## Discovery

This binding does not support discovery.

## Thing Configuration

The following configuration parameter applys to `ald1Unidirectional` and `ald1Bidirectional`.

| Name | Description | Type | Required |
|---------------|------------------------------------------|---------|----------|
| pollInterval | Time between polling the data in ms | Integer | yes |

The Thing needs a Modbus serial slave Bridge to operate.

One of the following serial settings need to be configured in the Bridge:

- 9600 baud, 2 stop bit, no parity
- 9600 baud, 1 stop bit, even parity
- 9600 baud, 1 stop bit, odd parity

## Channels

The following Channels apply to `ald1Unidirectional` and `ald1Bidirectional` if not stated otherwise.

| Name | Type | Description |
|---------------------|--------------------------|---------------------------------------------------------------|
| total_energy | Number:Energy | Energy Total |
| partial_energy | Number:Energy | Energy Counter Resettable (only unidirectional meter) |
| feeding_back_energy | Number:Energy | Energy Feeding Back (only bidirectional meter) |
| voltage | Number:ElectricPotential | Effective Voltage |
| current | Number:ElectricCurrent | Effective Current |
| active_power | Number:Power | Effective Active Power (negative numbers mean feeding back) |
| reactive_power | Number:Power | Effective Reactive Power (negative numbers mean feeding back) |
| power_factor | Number:Dimensionless | Power Factor |

## Full Example

### .items

```
Number:Energy ALD1_Total_Energy "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:total_energy"}
Number:Energy ALD1_Feeding_Back_Energy "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:feeding_back_energy"}
Number:ElectricPotential ALD1_Voltage "[%d %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:voltage"}
Number:ElectricCurrent ALD1_Current "[%.1f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:current"}
Number:Power ALD1_Active_Power "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:active_power"}
Number:Power ALD1_Reactive_Power "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:reactive_power"}
Number:Dimensionless ALD1_Power_Factor "[%.2f]" {channel="modbus:ald1Bidirectional:8b6e85623b:power_factor"}
```

### .sitemap

```
sitemap ald1 label="ALD1 Energy Meter"
{
Default item=ALD1_Total_Energy label="Total Energy"
Default item=ALD1_Feeding_Back_Energy label="Feeding Back Energy"
Default item=ALD1_Voltage label="Voltage"
Default item=ALD1_Current label="Current"
Default item=ALD1_Active_Power label="Active Power"
Default item=ALD1_Reactive_Power label="Reactive Power"
Default item=ALD1_Power_Factor label="Power Factor"
}
```
26 changes: 26 additions & 0 deletions bundles/org.openhab.binding.modbus.sbc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.1.0-SNAPSHOT</version>
</parent>

<artifactId>org.openhab.binding.modbus.sbc</artifactId>

<name>openHAB Add-ons :: Bundles :: Modbus SBC Binding</name>

<dependencies>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.modbus</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.sbc.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* The {@link ALD1Configuration} class contains fields mapping thing configuration parameters.
*
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
public class ALD1Configuration {
public int pollInterval;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.sbc.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.modbus.handler.BaseModbusThingHandler;
import org.openhab.core.io.transport.modbus.AsyncModbusFailure;
import org.openhab.core.io.transport.modbus.AsyncModbusReadResult;
import org.openhab.core.io.transport.modbus.ModbusBitUtilities;
import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode;
import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;

/**
* The {@link ALD1Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
public class ALD1Handler extends BaseModbusThingHandler {
private static final int FIRST_READ_REGISTER = 28;
private static final int READ_LENGTH = 13;
private static final int TRIES = 1;
private ALD1Configuration config = new ALD1Configuration();
private @Nullable ModbusReadRequestBlueprint blueprint;

public ALD1Handler(Thing thing) {
super(thing);
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {
ModbusReadRequestBlueprint localBlueprint = blueprint;
if (command instanceof RefreshType && localBlueprint != null) {
submitOneTimePoll(localBlueprint, this::readSuccessful, this::readError);
}
}

@Override
public void modbusInitialize() {
config = getConfigAs(ALD1Configuration.class);

if (config.pollInterval <= 0) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Invalid poll interval: " + config.pollInterval);
return;
}

ModbusReadRequestBlueprint localBlueprint = blueprint = new ModbusReadRequestBlueprint(getSlaveId(),
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, FIRST_READ_REGISTER - 1, READ_LENGTH, TRIES);

updateStatus(ThingStatus.UNKNOWN);

registerRegularPoll(localBlueprint, config.pollInterval, 0, this::readSuccessful, this::readError);
}

private void readSuccessful(AsyncModbusReadResult result) {
result.getRegisters().ifPresent(registers -> {
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
}

for (ALD1Registers channel : ALD1Registers.values()) {
int index = channel.getRegisterNumber() - FIRST_READ_REGISTER;

ModbusBitUtilities.extractStateFromRegisters(registers, index, channel.getType())
.map(d -> d.toBigDecimal().multiply(channel.getMultiplier()))
.map(bigDecimal -> new QuantityType<>(bigDecimal, channel.getUnit()))
.ifPresent(v -> updateState(createChannelUid(channel), v));
}
});
}

private void readError(AsyncModbusFailure<ModbusReadRequestBlueprint> error) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Failed to retrieve data: " + error.getCause().getMessage());
}

private ChannelUID createChannelUid(ALD1Registers channel) {
return new ChannelUID(thing.getUID(), channel.toString().toLowerCase());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.sbc.internal;

import static org.openhab.core.io.transport.modbus.ModbusConstants.ValueType.*;

import java.math.BigDecimal;

import javax.measure.Unit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.io.transport.modbus.ModbusConstants;
import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType;
import org.openhab.core.library.unit.Units;

/**
* The {@link ALD1Registers} is responsible for defining Modbus registers and their units.
*
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
public enum ALD1Registers {
// the following register numbers are 1-based. They need to be converted before sending them on the wire.
TOTAL_ENERGY(0.01f, 28, UINT32, Units.KILOWATT_HOUR),
PARTIAL_ENERGY(0.01f, 30, UINT32, Units.KILOWATT_HOUR), // only unidirectional meters
FEEDING_BACK_ENERGY(0.01f, 30, UINT32, Units.KILOWATT_HOUR), // only bidirectional meters
VOLTAGE(1, 36, UINT16, Units.VOLT),
CURRENT(0.1f, 37, UINT16, Units.AMPERE),
ACTIVE_POWER(10, 38, INT16, Units.WATT),
REACTIVE_POWER(10, 39, INT16, Units.VAR),
POWER_FACTOR(0.01f, 40, INT16, Units.ONE);

private BigDecimal multiplier;
private int registerNumber;
private ModbusConstants.ValueType type;
private Unit<?> unit;

private ALD1Registers(float multiplier, int registerNumber, ValueType type, Unit<?> unit) {
this.multiplier = new BigDecimal(multiplier);
this.registerNumber = registerNumber;
this.type = type;
this.unit = unit;
}

public Unit<?> getUnit() {
return unit;
}

public BigDecimal getMultiplier() {
return multiplier;
}

public int getRegisterNumber() {
return registerNumber;
}

public ModbusConstants.ValueType getType() {
return type;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.modbus.sbc.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.modbus.ModbusBindingConstants;
import org.openhab.core.thing.ThingTypeUID;

/**
* The {@link SBCBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Fabian Wolter - Initial contribution
*/
@NonNullByDefault
public class SBCBindingConstants {
public static final ThingTypeUID THING_TYPE_ALD1_UNIDIRECTIONAL = new ThingTypeUID(
ModbusBindingConstants.BINDING_ID, "ald1Unidirectional");
public static final ThingTypeUID THING_TYPE_ALD1_BIDIRECTIONAL = new ThingTypeUID(ModbusBindingConstants.BINDING_ID,
"ald1Bidirectional");
}
Loading

0 comments on commit 0be7f60

Please sign in to comment.