Skip to content

Commit 0be7f60

Browse files
authored
[modbus.sbc] Initial contribution (openhab#9174)
Signed-off-by: Fabian Wolter <[email protected]>
1 parent ff3ff93 commit 0be7f60

File tree

14 files changed

+518
-0
lines changed

14 files changed

+518
-0
lines changed

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
/bundles/org.openhab.binding.modbus/ @ssalonen
159159
/bundles/org.openhab.binding.modbus.e3dc/ @weymann
160160
/bundles/org.openhab.binding.modbus.helioseasycontrols/ @bern77
161+
/bundles/org.openhab.binding.modbus.sbc/ @fwolter
161162
/bundles/org.openhab.binding.modbus.stiebeleltron/ @pail23
162163
/bundles/org.openhab.binding.modbus.studer/ @giovannimirulla
163164
/bundles/org.openhab.binding.modbus.sunspec/ @mrbig

bom/openhab-addons/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,11 @@
776776
<artifactId>org.openhab.binding.modbus.helioseasycontrols</artifactId>
777777
<version>${project.version}</version>
778778
</dependency>
779+
<dependency>
780+
<groupId>org.openhab.addons.bundles</groupId>
781+
<artifactId>org.openhab.binding.modbus.sbc</artifactId>
782+
<version>${project.version}</version>
783+
</dependency>
779784
<dependency>
780785
<groupId>org.openhab.addons.bundles</groupId>
781786
<artifactId>org.openhab.binding.modbus.stiebeleltron</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
This content is produced and maintained by the openHAB project.
2+
3+
* Project home: https://www.openhab.org
4+
5+
== Declared Project Licenses
6+
7+
This program and the accompanying materials are made available under the terms
8+
of the Eclipse Public License 2.0 which is available at
9+
https://www.eclipse.org/legal/epl-2.0/.
10+
11+
== Source Code
12+
13+
https://github.com/openhab/openhab-addons
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Modbus Saia Burgess Controls Binding
2+
3+
This binding interfaces the energy meter series ALD1 by Saia Burgess Controls (SBC) via Modbus.
4+
5+
## Supported Things
6+
7+
The following Things are supported:
8+
9+
- `ald1Unidirectional`: 1-phase 32A one-way energy meter ALD1D5FD00A3A00
10+
- `ald1Bidirectional`: 1-phase 32A two-way energy meter ALD1B5FD00A3A00
11+
12+
## Discovery
13+
14+
This binding does not support discovery.
15+
16+
## Thing Configuration
17+
18+
The following configuration parameter applys to `ald1Unidirectional` and `ald1Bidirectional`.
19+
20+
| Name | Description | Type | Required |
21+
|---------------|------------------------------------------|---------|----------|
22+
| pollInterval | Time between polling the data in ms | Integer | yes |
23+
24+
The Thing needs a Modbus serial slave Bridge to operate.
25+
26+
One of the following serial settings need to be configured in the Bridge:
27+
28+
- 9600 baud, 2 stop bit, no parity
29+
- 9600 baud, 1 stop bit, even parity
30+
- 9600 baud, 1 stop bit, odd parity
31+
32+
## Channels
33+
34+
The following Channels apply to `ald1Unidirectional` and `ald1Bidirectional` if not stated otherwise.
35+
36+
| Name | Type | Description |
37+
|---------------------|--------------------------|---------------------------------------------------------------|
38+
| total_energy | Number:Energy | Energy Total |
39+
| partial_energy | Number:Energy | Energy Counter Resettable (only unidirectional meter) |
40+
| feeding_back_energy | Number:Energy | Energy Feeding Back (only bidirectional meter) |
41+
| voltage | Number:ElectricPotential | Effective Voltage |
42+
| current | Number:ElectricCurrent | Effective Current |
43+
| active_power | Number:Power | Effective Active Power (negative numbers mean feeding back) |
44+
| reactive_power | Number:Power | Effective Reactive Power (negative numbers mean feeding back) |
45+
| power_factor | Number:Dimensionless | Power Factor |
46+
47+
## Full Example
48+
49+
### .items
50+
51+
```
52+
Number:Energy ALD1_Total_Energy "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:total_energy"}
53+
Number:Energy ALD1_Feeding_Back_Energy "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:feeding_back_energy"}
54+
Number:ElectricPotential ALD1_Voltage "[%d %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:voltage"}
55+
Number:ElectricCurrent ALD1_Current "[%.1f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:current"}
56+
Number:Power ALD1_Active_Power "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:active_power"}
57+
Number:Power ALD1_Reactive_Power "[%.2f %unit%]" {channel="modbus:ald1Bidirectional:8b6e85623b:reactive_power"}
58+
Number:Dimensionless ALD1_Power_Factor "[%.2f]" {channel="modbus:ald1Bidirectional:8b6e85623b:power_factor"}
59+
```
60+
61+
### .sitemap
62+
63+
```
64+
sitemap ald1 label="ALD1 Energy Meter"
65+
{
66+
Default item=ALD1_Total_Energy label="Total Energy"
67+
Default item=ALD1_Feeding_Back_Energy label="Feeding Back Energy"
68+
Default item=ALD1_Voltage label="Voltage"
69+
Default item=ALD1_Current label="Current"
70+
Default item=ALD1_Active_Power label="Active Power"
71+
Default item=ALD1_Reactive_Power label="Reactive Power"
72+
Default item=ALD1_Power_Factor label="Power Factor"
73+
}
74+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>org.openhab.addons.bundles</groupId>
9+
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
10+
<version>3.1.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>org.openhab.binding.modbus.sbc</artifactId>
14+
15+
<name>openHAB Add-ons :: Bundles :: Modbus SBC Binding</name>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.openhab.addons.bundles</groupId>
20+
<artifactId>org.openhab.binding.modbus</artifactId>
21+
<version>${project.version}</version>
22+
<scope>provided</scope>
23+
</dependency>
24+
</dependencies>
25+
26+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.modbus.sbc.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
17+
/**
18+
* The {@link ALD1Configuration} class contains fields mapping thing configuration parameters.
19+
*
20+
* @author Fabian Wolter - Initial contribution
21+
*/
22+
@NonNullByDefault
23+
public class ALD1Configuration {
24+
public int pollInterval;
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.modbus.sbc.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.eclipse.jdt.annotation.Nullable;
17+
import org.openhab.binding.modbus.handler.BaseModbusThingHandler;
18+
import org.openhab.core.io.transport.modbus.AsyncModbusFailure;
19+
import org.openhab.core.io.transport.modbus.AsyncModbusReadResult;
20+
import org.openhab.core.io.transport.modbus.ModbusBitUtilities;
21+
import org.openhab.core.io.transport.modbus.ModbusReadFunctionCode;
22+
import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint;
23+
import org.openhab.core.library.types.QuantityType;
24+
import org.openhab.core.thing.ChannelUID;
25+
import org.openhab.core.thing.Thing;
26+
import org.openhab.core.thing.ThingStatus;
27+
import org.openhab.core.thing.ThingStatusDetail;
28+
import org.openhab.core.types.Command;
29+
import org.openhab.core.types.RefreshType;
30+
31+
/**
32+
* The {@link ALD1Handler} is responsible for handling commands, which are
33+
* sent to one of the channels.
34+
*
35+
* @author Fabian Wolter - Initial contribution
36+
*/
37+
@NonNullByDefault
38+
public class ALD1Handler extends BaseModbusThingHandler {
39+
private static final int FIRST_READ_REGISTER = 28;
40+
private static final int READ_LENGTH = 13;
41+
private static final int TRIES = 1;
42+
private ALD1Configuration config = new ALD1Configuration();
43+
private @Nullable ModbusReadRequestBlueprint blueprint;
44+
45+
public ALD1Handler(Thing thing) {
46+
super(thing);
47+
}
48+
49+
@Override
50+
public void handleCommand(ChannelUID channelUID, Command command) {
51+
ModbusReadRequestBlueprint localBlueprint = blueprint;
52+
if (command instanceof RefreshType && localBlueprint != null) {
53+
submitOneTimePoll(localBlueprint, this::readSuccessful, this::readError);
54+
}
55+
}
56+
57+
@Override
58+
public void modbusInitialize() {
59+
config = getConfigAs(ALD1Configuration.class);
60+
61+
if (config.pollInterval <= 0) {
62+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
63+
"Invalid poll interval: " + config.pollInterval);
64+
return;
65+
}
66+
67+
ModbusReadRequestBlueprint localBlueprint = blueprint = new ModbusReadRequestBlueprint(getSlaveId(),
68+
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, FIRST_READ_REGISTER - 1, READ_LENGTH, TRIES);
69+
70+
updateStatus(ThingStatus.UNKNOWN);
71+
72+
registerRegularPoll(localBlueprint, config.pollInterval, 0, this::readSuccessful, this::readError);
73+
}
74+
75+
private void readSuccessful(AsyncModbusReadResult result) {
76+
result.getRegisters().ifPresent(registers -> {
77+
if (getThing().getStatus() != ThingStatus.ONLINE) {
78+
updateStatus(ThingStatus.ONLINE);
79+
}
80+
81+
for (ALD1Registers channel : ALD1Registers.values()) {
82+
int index = channel.getRegisterNumber() - FIRST_READ_REGISTER;
83+
84+
ModbusBitUtilities.extractStateFromRegisters(registers, index, channel.getType())
85+
.map(d -> d.toBigDecimal().multiply(channel.getMultiplier()))
86+
.map(bigDecimal -> new QuantityType<>(bigDecimal, channel.getUnit()))
87+
.ifPresent(v -> updateState(createChannelUid(channel), v));
88+
}
89+
});
90+
}
91+
92+
private void readError(AsyncModbusFailure<ModbusReadRequestBlueprint> error) {
93+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
94+
"Failed to retrieve data: " + error.getCause().getMessage());
95+
}
96+
97+
private ChannelUID createChannelUid(ALD1Registers channel) {
98+
return new ChannelUID(thing.getUID(), channel.toString().toLowerCase());
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.modbus.sbc.internal;
14+
15+
import static org.openhab.core.io.transport.modbus.ModbusConstants.ValueType.*;
16+
17+
import java.math.BigDecimal;
18+
19+
import javax.measure.Unit;
20+
21+
import org.eclipse.jdt.annotation.NonNullByDefault;
22+
import org.openhab.core.io.transport.modbus.ModbusConstants;
23+
import org.openhab.core.io.transport.modbus.ModbusConstants.ValueType;
24+
import org.openhab.core.library.unit.Units;
25+
26+
/**
27+
* The {@link ALD1Registers} is responsible for defining Modbus registers and their units.
28+
*
29+
* @author Fabian Wolter - Initial contribution
30+
*/
31+
@NonNullByDefault
32+
public enum ALD1Registers {
33+
// the following register numbers are 1-based. They need to be converted before sending them on the wire.
34+
TOTAL_ENERGY(0.01f, 28, UINT32, Units.KILOWATT_HOUR),
35+
PARTIAL_ENERGY(0.01f, 30, UINT32, Units.KILOWATT_HOUR), // only unidirectional meters
36+
FEEDING_BACK_ENERGY(0.01f, 30, UINT32, Units.KILOWATT_HOUR), // only bidirectional meters
37+
VOLTAGE(1, 36, UINT16, Units.VOLT),
38+
CURRENT(0.1f, 37, UINT16, Units.AMPERE),
39+
ACTIVE_POWER(10, 38, INT16, Units.WATT),
40+
REACTIVE_POWER(10, 39, INT16, Units.VAR),
41+
POWER_FACTOR(0.01f, 40, INT16, Units.ONE);
42+
43+
private BigDecimal multiplier;
44+
private int registerNumber;
45+
private ModbusConstants.ValueType type;
46+
private Unit<?> unit;
47+
48+
private ALD1Registers(float multiplier, int registerNumber, ValueType type, Unit<?> unit) {
49+
this.multiplier = new BigDecimal(multiplier);
50+
this.registerNumber = registerNumber;
51+
this.type = type;
52+
this.unit = unit;
53+
}
54+
55+
public Unit<?> getUnit() {
56+
return unit;
57+
}
58+
59+
public BigDecimal getMultiplier() {
60+
return multiplier;
61+
}
62+
63+
public int getRegisterNumber() {
64+
return registerNumber;
65+
}
66+
67+
public ModbusConstants.ValueType getType() {
68+
return type;
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright (c) 2010-2021 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.modbus.sbc.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.openhab.binding.modbus.ModbusBindingConstants;
17+
import org.openhab.core.thing.ThingTypeUID;
18+
19+
/**
20+
* The {@link SBCBindingConstants} class defines common constants, which are
21+
* used across the whole binding.
22+
*
23+
* @author Fabian Wolter - Initial contribution
24+
*/
25+
@NonNullByDefault
26+
public class SBCBindingConstants {
27+
public static final ThingTypeUID THING_TYPE_ALD1_UNIDIRECTIONAL = new ThingTypeUID(
28+
ModbusBindingConstants.BINDING_ID, "ald1Unidirectional");
29+
public static final ThingTypeUID THING_TYPE_ALD1_BIDIRECTIONAL = new ThingTypeUID(ModbusBindingConstants.BINDING_ID,
30+
"ald1Bidirectional");
31+
}

0 commit comments

Comments
 (0)