mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-11 15:42:10 +01:00
a3a4745730
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
190 lines
8.0 KiB
Markdown
190 lines
8.0 KiB
Markdown
# For Developers
|
|
|
|
## Debugging an addon
|
|
|
|
Please follow IDE setup guide at <https://www.openhab.org/docs/developer/ide/eclipse.html>.
|
|
|
|
When configuring dependencies in `openhab-distro/launch/app/pom.xml`, add all dependencies, including the transitive dependencies:
|
|
|
|
```xml
|
|
<dependency>
|
|
<groupId>org.openhab.addons.bundles</groupId>
|
|
<artifactId>org.openhab.binding.sbus</artifactId>
|
|
<version>${project.version}</version>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.openhab.core.bundles</groupId>
|
|
<artifactId>org.openhab.core.io.transport.sbus</artifactId>
|
|
<version>${project.version}</version>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>net.wimpi</groupId>
|
|
<artifactId>jamod</artifactId>
|
|
<version>1.2.4.OH</version>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
```
|
|
|
|
## Testing Serial Implementation
|
|
|
|
You can use test serial slaves without any hardware on Linux using these steps:
|
|
|
|
1. Set-up virtual null modem emulator using [tty0tty](https://github.com/freemed/tty0tty)
|
|
1. Download [diagslave](https://www.modbusdriver.com/diagslave.html) and start modbus serial slave up using this command:
|
|
|
|
```shell
|
|
./diagslave -m rtu -a 1 -b 38400 -d 8 -s 1 -p none -4 10 /dev/pts/7
|
|
```
|
|
|
|
1. Configure openHAB's modbus slave to connect to `/dev/pts/8`.
|
|
|
|
1. Modify `start.sh` or `start_debug.sh` to include the unconventional port name by adding the following argument to `java`:
|
|
|
|
```text
|
|
-Dgnu.io.rxtx.SerialPorts=/dev/pts/8
|
|
```
|
|
|
|
Naturally this is not the same thing as the real thing but helps to identify simple issues.
|
|
|
|
## Testing UDP Implementation
|
|
|
|
1. Download [diagslave](https://www.modbusdriver.com/diagslave.html) and start modbus udp server (slave) using this command:
|
|
|
|
```shell
|
|
./diagslave -m udp -a 1 -p 6000
|
|
```
|
|
|
|
1. Configure openHAB's modbus slave to connect to `127.0.0.1:6000`.
|
|
|
|
## Writing Data
|
|
|
|
See this [community post](https://community.openhab.org/t/something-is-rounding-my-float-values-in-sitemap/13704/32?u=ssalonen) explaining how `pollmb` and `diagslave` can be used to debug modbus communication.
|
|
|
|
You can also use `modpoll` to write data:
|
|
|
|
```shell
|
|
# write value=5 to holding register 40001 (index=0 in the binding)
|
|
./modpoll -m udp -a 1 -r 1 -t4 -p 6000 127.0.0.1 5
|
|
# set coil 00001 (index=0 in the binding) to TRUE
|
|
./modpoll -m udp -a 1 -r 1 -t0 -p 6000 127.0.0.1 1
|
|
# write float32
|
|
./modpoll -m udp -a 1 -r 1 -t4:float -p 6000 127.0.0.1 3.14
|
|
```
|
|
|
|
## Extending Modbus Binding
|
|
|
|
This Modbus binding can be extended by other OSGi bundles to add more specific support for Modbus enabled devices.
|
|
To do so to you have to create a new OSGi bundle which has the same binding id as this binding.
|
|
The best way is to use the `ModbusBindingConstants.BINDING_ID` constant.
|
|
|
|
### Thing Handler
|
|
|
|
You will have to create one or more handler classes for the devices you want to support.
|
|
For the modbus connection setup and handling you can use the Modbus UDP Slave or Modbus Serial Slave handlers.
|
|
Your handler should use these handlers as bridges and you can set up your regular or one shot modbus requests to read from the slave.
|
|
This is done by extending your `ThingHandler` by `BaseModbusThingHandler`.
|
|
You can use the inherited methods `submitOneTimePoll()` and `registerRegularPoll()` to poll values and `submitOneTimeWrite()` to send values to a slave.
|
|
The `BaseModbusThingHandler` takes care that every regular poll task is cancelled, when the Thing is disposed.
|
|
Despite that, you can cancel the task manually by storing the return value of `registerRegularPoll()` and use it as an argument to `unregisterRegularPoll()`.
|
|
|
|
Please keep in mind that these reads are asynchronous and they will call your callback once the read is done.
|
|
|
|
Once you have your data read from the modbus device you can parse and transform them then update your channels to publish these data to the openHAB system.
|
|
|
|
See the following example:
|
|
|
|
```java
|
|
@NonNullByDefault
|
|
public class MyHandler extends BaseModbusThingHandler {
|
|
public MyHandler(Thing thing) {
|
|
super(thing);
|
|
}
|
|
|
|
@Override
|
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
|
if (command instanceof RefreshType) {
|
|
ModbusReadRequestBlueprint blueprint = new ModbusReadRequestBlueprint(getSlaveId(),
|
|
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 0, 1, 2);
|
|
|
|
submitOneTimePoll(blueprint, this::readSuccessful, this::readError);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void modbusInitialize() {
|
|
// do other Thing initialization
|
|
|
|
ModbusReadRequestBlueprint blueprint = new ModbusReadRequestBlueprint(getSlaveId(),
|
|
ModbusReadFunctionCode.READ_MULTIPLE_REGISTERS, 0, 1, 2);
|
|
|
|
registerRegularPoll(blueprint, 1000, 0, this::readSuccessful, this::readError);
|
|
}
|
|
|
|
private void readSuccessful(AsyncModbusReadResult result) {
|
|
result.getRegisters().ifPresent(registers -> {
|
|
Optional<DecimalType> value = ModbusBitUtilities.extractStateFromRegisters(registers, 0, ValueType.INT16);
|
|
// process value
|
|
});
|
|
}
|
|
|
|
private void readError(AsyncModbusFailure<ModbusReadRequestBlueprint> error) {
|
|
// set the Thing offline
|
|
}
|
|
}
|
|
```
|
|
|
|
### Discovery
|
|
|
|
If you write a device specific handler then adding discovery for this device is very welcome.
|
|
You will have to write a discovery participant class which implements the `ModbusDiscoveryParticipant` interface and registers itself as a component. Example:
|
|
|
|
```java
|
|
|
|
@Component
|
|
@NonNullByDefault
|
|
public class SunspecDiscoveryParticipant implements ModbusDiscoveryParticipant {
|
|
...
|
|
}
|
|
```
|
|
|
|
There are two methods you have to implement:
|
|
|
|
- `getSupportedThingTypeUIDs` should return a list of the thing type UIDs that are supported by this discovery participant. This is fairly straightforward.
|
|
|
|
- `startDiscovery` method will be called when a discovery process has began. This method receives two parameters:
|
|
|
|
- `ModbusEndpointThingHandler` is the endpoint's handler that should be tested if it is known by your bundle. You can start your read requests against this handler.
|
|
|
|
- `ModbusDiscoveryListener` this listener instance should be used to report any known devices found and to notify the main discovery process when your binding has finished the discovery.
|
|
|
|
Please try to avoid write requests to the endpoint because it could be some unknown device that write requests could misconfigure.
|
|
|
|
When a known device is found a `DiscoveryResult` object has to be created then the `thingDiscovered` method has to be called.
|
|
The `DiscoveryResult` supports properties, and you should use this to store any data that will be useful when the actual thing will be created.
|
|
For example you could store the start Modbus address of the device or vendor/model informations.
|
|
|
|
When the discovery process is finished either by detecting a device or by realizing it is not supported you should call the `discoveryFinished` method.
|
|
This will tear down any resources allocated for the discovery process.
|
|
|
|
### Discovery Architecture
|
|
|
|
The following diagram shows the concept how discovery is implemented in this binding. (Note that some intermediate classes and interfaces are not shown for clarity.)
|
|
|
|
![Discovery architecture](doc/images/ModbusExtensibleDiscovery.png)
|
|
|
|
As stated above the discovery process can be extended by OSGi bundles.
|
|
For this they have to define their own `ModbusDisvoceryParticipant` that gets registered at the `ModbusDiscoveryService`.
|
|
This object also keeps track of any of the Modbus handlers.
|
|
Handler level discovery logic is implemented in the `ModbusEndpointDiscoveryService` which gets instantiated for each Modbus `BridgeHandler`.
|
|
|
|
The communication flow is detailed in the diagram below:
|
|
|
|
![Discovery process](doc/images/DiscoveryProcess.png)
|
|
|
|
As can be seen the process is initiated by the `ModbusDiscoveryService` which calls each of the `ModbusEndpointDiscoveryService` instances to start the discovery on the available participants.
|
|
Then a reference to the `ThingHandler` is passed to each of the participants who can use this to do the actual discovery.
|
|
|
|
Any things discovered are reported back in this chain and ultimately sent to openHAB core.
|