Skip to content

Commit

Permalink
[phc] Improve serial communication and add support for dimmer (openha…
Browse files Browse the repository at this point in the history
…b#6447)

* Add support for dimmer
* Improve receiving, recognition of serial messages
* Null Annotations + gnu.io to core + Formatting
* Improve sending of serial messages
* Add bus connection to README
* minor corrections
* split method and use BolckingQueue in InternalBuffer
* use diamond operator and format
* Correct README
* Remove gnu.io from pom.xml added in openhab#7589

Signed-off-by: Jonas Hohaus <jh@gnlpf.net>
Signed-off-by: CSchlipp <christian@schlipp.de>
  • Loading branch information
gnlpfjh authored and CSchlipp committed Jul 26, 2020
1 parent bbcaa3c commit 90eb8e9
Show file tree
Hide file tree
Showing 13 changed files with 747 additions and 452 deletions.
89 changes: 65 additions & 24 deletions bundles/org.openhab.binding.phc/README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
---
layout: documentation
---

{% include base.html %}

# PHC Binding

This binding allows you to integrate modules(at the Moment AM, EM and JRM) of PHC, without the PHC control (STM), in openHAB.
This binding allows you to integrate modules(at the Moment AM, EM, JRM and DIM) of PHC, without the PHC control (STM), in openHAB.

The serial protocol is mainly extracted, with thanks to the developers from the projects [PHCtoUDP](https://sourceforge.net/projects/phctoudp/) and [OpenHC](https://sourceforge.net/projects/openhc/?source=directory).

## Bridge

The Bridge manages the communication between the things and the modules via a serial port (RS485). It represents the STM.
At the Moment you can only use one Bridge (like one STM).

#### Configurations

**Serial Port:** Type the serial port of the RS485 adaptor, e.g. COM3 (Windows) or /dev/ttyUSB0 (Linux).
The basics of the module bus protocol can also be found in the [Wiki of the PHC-Forum (german)](https://wiki.phc-forum.de/index.php/PHC-Protokoll_des_internen_Bus).
While the Wiki is offline you can find a PDF version [here](https://phc-forum.de/index.php/forum/phc-programmierung/129-phc-protokoll?start=15#1329).

#### Serial Communication
## Serial Communication

The binding was tested with QinHeng Electronics HL-340 USB-Serial adapter (RS485) and the Digitus DA-70157 (FTDI/FT323RL) on Raspbian Ubilinux (Up Board) and Windows 10:

Expand All @@ -31,18 +19,56 @@ The binding was tested with QinHeng Electronics HL-340 USB-Serial adapter (RS485
| | FTDI | doesn´t work |
| | on board | bad |
| Up Board/ubilinux(Jessie)| HL-340 | not reliable |
| | FTDI | ok |
| | FTDI | good |

Sometimes it is a bit slowly and you have to switch two times for reaction, but all in all it works ok.
I'm trying to get a faster solution for communication in the next few weeks.
If there are many modules on one bridge, the initialization can take a few minutes. If it does not work you can plug in the modules one after the other.
Sometimes after initialization, you might have to switch two times or the reaction could be a bit slow, but after you used a channel it should all work fine.

For all devices running with Linux that use the ch341 driver (HL-340), the new version (ch34x) is needed.
A guide how to install this can be found here: [CH340/341 UART Driver for Raspberry Pi](https://github.com/aperepel/raspberrypi-ch340-driver).

If you don´t have the same kernel as used in the guide you have to compile the module yourself. In the guide is described a specific way for the Raspberry Pi. With another Linux version you can go the normal way with linux-headers.

According to the [Wiki of the PHC-Forum](https://wiki.phc-forum.de/index.php/PHC-Protokoll_des_internen_Bus#USB_RS-485_Adapter) the newer version of the FTDI adapter doesn't really work anymore either.

In Linux amongst others the user 'openhab' must be added to the group 'dialout': ```sudo usermod -a -G dialout openhab``` For more information read the [installation guide](https://www.openhab.org/docs/installation/linux.html#recommended-additional-setup-steps).

### Connection

There are two alternatives, the first of which is much simpler.

#### Connection via power supply (simpler, preferred)

The simplest way would be to connect the RS485 adaptor to the PHC power supply like in the table below and Out at the power supply to the first module like the STM before.

| adaptor | PHC power supply |
|----------|------------------|
| 485+ | +A |
| 485- | -B |

#### Make a direct RJ12 connection

Connect a RJ12 plug with the RS485 adaptor and the power supply as follows.

| RJ12 like in picture below | The cores on the other side |
|----------------------------|-----------------------------|
| 0V | 0V on power supply |
| B- | 485- on adaptor |
| A+ | 485+ on adaptor |
| 24+ | +24V on power supply |

![RJ12 Connector](doc/RJ12-Connector.png)

## Bridge

The Bridge manages the communication between the things and the modules via a serial port (RS485).
It represents the STM.
At the Moment you can only use one Bridge (like one STM).

#### Configurations

**Serial Port:** Type the serial port of the RS485 adaptor, e.g. COM3 (Windows) or /dev/ttyUSB0 (Linux).

## Supported Things

- **AM module:** This represents the AM module with 8 outgoing channels (relays).
Expand All @@ -51,21 +77,25 @@ In Linux amongst others the user 'openhab' must be added to the group 'dialout':

- **JRM module:** This represents the JRM module with 4 channels for Shutters.

- **DIM:** This represents the DM module with 2 dimmer channels.

## Discovery

Not implemented yet.

## Thing Configuration

A thing accords with a module in the PHC software and the channels (with linked items) accord with the inputs and outputs.
Please note, if you define the things manually (not in the UI) that the ThingID always have to be the address.
Please note, if you define the things manually (not in the UI) that the ThingID always have to be the address (like the PID switches on the module).

#### Parameters

- **Address:** Type the address of the module like the DIP switches (you can also find in the PHC software) of the module, e.g. 10110. (mandatory)

- **UpDownTime[1-4] (only JRM):** (advanced) The time in seconds that the shutter needs to move up or down. The default, if no value is specified, is 30 seconds.

- **DimTime[1-2] (only DIM):** (advanced) The time in seconds in that the dimmer should move 100%. The default is 2 seconds, then for example dimming from 0 to 100% takes 1 second.

## Channels

| Thing Type | Channel-Group Id | Channels | Item Type |
Expand All @@ -75,14 +105,20 @@ Please note, if you define the things manually (not in the UI) that the ThingID
| EM | emLed | 00-07 | Switch |
| JRM | jrm | 00-03 | Rollershutter |
| JRM | jrmT | 00-03 | Number |
| DIM | dim | 00-01 | Dimmer |
| DIM | dimT | 00-01 | Number |

**Channel UID:** ```phc:<Thing Type>:<ThingID>:<Channel Group>#<Channel>``` e.g. ```phc:AM:01101:am#03```

- **am:** Outgoing switch channels (relay).
- **em:** Incoming channels.
- **emLed:** Outgoing switch channels e.g. for LEDs in light shutters.
- **jrm:** Outgoing shutter channels.
- **jrmT:** Time for shutter channels in seconds with an accuracy of 1/10 seconds. These channels are used instead of the configuration parameters. If you send the time via this channel, the Binding uses this time till you send another. After reboot the config parameter is used by default.
- **jrmT:** Time for shutter channels in seconds with an accuracy of 1/10 seconds.
These channels are used instead of the configuration parameters.
If you send the time via this channel, the Binding uses this time till you send another.
After reboot the config parameter is used by default.
- **dim:** Outgoing dimmer channels.

## Full Example

Expand All @@ -91,9 +127,10 @@ Please note, if you define the things manually (not in the UI) that the ThingID
```
Bridge phc:bridge:demo [port="/dev/ttyUSB0"]{
// The ThingID have to be the address.
Thing AM 10110 [address="01101"]
Thing AM 01101 [address="01101"]
Thing EM 00110 [address="00110"]
Thing JRM 10111 [address="10111", upDownTime3="60", upDownTime4="20"]
Thing DIM 00000 [address="00000"]
```

.items
Expand All @@ -114,12 +151,16 @@ Rollershutter Shutter_4 {channel="phc:JRM:10111:jrm#03"}
Number ShutterTime_1 {channel="phc:JRM:10111:jrmT#00"}
//DIM Module
Dimmer Dimmer_1 {channel="phc:DIM:00000:dim#00}
Dimmer Dimmer_2 {channel="phc:DIM:00000:dim#01}
// EM Module
Switch InputLed_1 {channel="phc:EM:00110:emLed#03"}
Switch InputLed_3 {channel="phc:EM:00110:emLed#03"}
Switch Input_1 {channel="phc:EM:00110:em#00"}
Switch Input_2 {channel="phc:EM:00110:em#01"}
Switch Input_3 {channel="phc:EM:00110:em#01"}
Switch Input_3 {channel="phc:EM:00110:em#02"}
...
Switch Input_16 {channel="phc:EM:00110:em#15"}
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions bundles/org.openhab.binding.phc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,4 @@

<name>openHAB Add-ons :: Bundles :: PHC Binding</name>

<properties>
<bnd.importpackage>gnu.io;version="[3.12,6)"</bnd.importpackage>
</properties>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
*/
package org.openhab.binding.phc.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ThingTypeUID;

/**
* The {@link PHCBinding} class defines common constants, which are
* used across the whole binding.
* The {@link PHCBinding} class defines common constants, which are used across
* the whole binding.
*
* @author Jonas Hohaus - Initial contribution
*/
@NonNullByDefault
public class PHCBindingConstants {

public static final String BINDING_ID = "phc";
Expand All @@ -30,13 +32,15 @@ public class PHCBindingConstants {
public static final ThingTypeUID THING_TYPE_AM = new ThingTypeUID(BINDING_ID, "AM");
public static final ThingTypeUID THING_TYPE_EM = new ThingTypeUID(BINDING_ID, "EM");
public static final ThingTypeUID THING_TYPE_JRM = new ThingTypeUID(BINDING_ID, "JRM");
public static final ThingTypeUID THING_TYPE_DIM = new ThingTypeUID(BINDING_ID, "DIM");

// List of all Channel Group IDs
public static final String CHANNELS_AM = "am";
public static final String CHANNELS_EM = "em";
public static final String CHANNELS_EM_LED = "emLed";
public static final String CHANNELS_JRM = "jrm";
public static final String CHANNELS_JRM_TIME = "jrmT";
public static final String CHANNELS_DIM = "dim";

// List of all configuration parameters
public static final String PORT = "port";
Expand All @@ -45,4 +49,6 @@ public class PHCBindingConstants {
public static final String UP_DOWN_TIME_2 = "upDownTime2";
public static final String UP_DOWN_TIME_3 = "upDownTime3";
public static final String UP_DOWN_TIME_4 = "upDownTime4";
public static final String DIM_TIME_1 = "dimTime1";
public static final String DIM_TIME_2 = "dimTime2";
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.Thing;
Expand All @@ -27,37 +29,52 @@
import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.openhab.binding.phc.internal.handler.PHCBridgeHandler;
import org.openhab.binding.phc.internal.handler.PHCHandler;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* The {@link PHCHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Jonas Hohaus - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.phc")
public class PHCHandlerFactory extends BaseThingHandlerFactory {

private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_BRIDGE, THING_TYPE_AM, THING_TYPE_EM, THING_TYPE_JRM).collect(Collectors.toSet()));
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_BRIDGE, THING_TYPE_AM, THING_TYPE_EM, THING_TYPE_JRM, THING_TYPE_DIM)
.collect(Collectors.toSet()));

private @NonNullByDefault({}) SerialPortManager serialPortManager;

@Reference
protected void setSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}

protected void unsetSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = null;
}

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}

@Override
public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID,
ThingUID bridgeUID) {
public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
@Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
Thing thing;

if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
thing = super.createThing(thingTypeUID, configuration, thingUID, null);
} else {
ThingUID phcThingUID = new ThingUID(thingTypeUID, configuration.get(ADDRESS).toString().toUpperCase());
ThingUID phcThingUID = new ThingUID(thingTypeUID, configuration.get(ADDRESS).toString());
thing = super.createThing(thingTypeUID, configuration, phcThingUID, bridgeUID);
}
} else {
Expand All @@ -69,13 +86,13 @@ public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
}

@Override
protected ThingHandler createHandler(Thing thing) {
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

ThingHandler handler = null;

if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
handler = new PHCBridgeHandler((Bridge) thing);
handler = new PHCBridgeHandler((Bridge) thing, serialPortManager);
} else if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
handler = new PHCHandler(thing);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
package org.openhab.binding.phc.internal;

import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.ThingUID;

/**
* The {@link PHCHelper} is responsible for finding the appropriate Thing(UID) to the Channel of the PHC module.
* The {@link PHCHelper} is responsible for finding the appropriate Thing(UID)
* to the Channel of the PHC module.
*
* @author Jonas Hohaus - Initial contribution
*/

@NonNullByDefault
public class PHCHelper {

/**
Expand All @@ -47,17 +49,13 @@ public static ThingUID getThingUIDreverse(ThingTypeUID thingTypeUID, byte module
* @param b
* @return
*/
public static Object byteToBinaryString(byte b) {
return StringUtils.leftPad(StringUtils.trim(Integer.toBinaryString(b & 0xFF)), 8, '0') + " ";
}

/**
* Convert the byte b into an hex String
*
* @param b
* @return
*/
public static Object byteToHexString(byte b) {
return Integer.toHexString(b & 0xFF) + " ";
public static Object bytesToBinaryString(byte[] bytes) {
StringBuilder bin = new StringBuilder();
for (byte b : bytes) {
bin.append(StringUtils.leftPad(StringUtils.trim(Integer.toBinaryString(b & 0xFF)), 8, '0'));
bin.append(' ');
}

return bin.toString();
}
}
Loading

0 comments on commit 90eb8e9

Please sign in to comment.