added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.mcp23017</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,20 @@
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
== Third-party Content
pi4j
* License: LGPL v3.0 License
* Project: http://pi4j.com
* Source: https://github.com/Pi4J/pi4j

View File

@@ -0,0 +1,99 @@
# MCP23017 Binding
This binding allows you to have native access for MCP23017 I/O expander on I2C bus.
It was tested with Raspberry Pi 2 and Raspberry Pi 3, but probably should work with other devices supported by [Pi4J](https://pi4j.com/) library.
On Raspberry Pi the user on which openHAB is running (default user name is "openhab") needs to be added to groups "i2c" and "gpio".
As the MCP23017 has 3 address pins, you are restricted to 8 devices on a I2C bus.
To use more devices you have to open further I2C busses.
Therefore you can use overlays to enable bit banging I2C busses on the Raspberry Pi connector, up to I2C6.
(https://github.com/raspberrypi/firmware/tree/master/boot/overlays)
## Dependencies
Make sure that the [wiringPi](http://wiringpi.com/) library has been installed and that the `gpio` command line tool is available to openHAB.
The shared library `libwiringPi.so` is required by the [Pi4J](https://pi4j.com/) Java library to access the GPIO ports.
Without satisfying this dependency you will see strange `NoClassDefFoundError: Could not initialize class ...` errors in the openHAB logs.
## Supported Things
This binding supports one thing type:
mcp23017 - which is a mcp23017 chip connected to an I2C bus on specified HEX address and bus number
## Thing Configuration
* Required configuration for mcp23017 thing:
| Parameter | Description | Default value |
|------------|-----------------------------------------------------------------------------------------------------------------------------------|---------------|
| address | MCP23017 I2C bus address. On Raspberry Pi it can be checked as a result of command: "i2cdetect -y 1". Value should be set in HEX. | "20" |
| bus_number | a bus number to which mcp23017 is connected. On RPI2 and RPI3 it will be "1", on RPI1 it will be "0". | "1" |
## Channels
mcp23017 supports 16 channels in 2 groups:
| Group | Channels | Additional parameters |
|--------|----------------------------------------------------------------|-------------------------------------------|
| input | A0, A1, A2, A3, A4, A5, A6, A7, B0, B1, B2, B3, B4, B5, B6, B7 | pull_mode (OFF, PULL_UP), default is OFF |
| output | A0, A1, A2, A3, A4, A5, A6, A7, B0, B1, B2, B3, B4, B5, B6, B7 | default_state (LOW, HIGH), default is LOW |
Channel determines MCP23017 PIN we want to use.
Group determines mode in which PIN shoud work.
When PIN should work as DIGITAL_INPUT, channel from group "input" should be used.
When PIN should work as DIGITAL_OUTPUT, channel from group "output" should be used.
## Full Example
Let's imagine a setup with:
1. a wall switch connected to pin B1 on the MCP23017 chip which should turn on/off your LED light when pressed (released).
2. a relay which is connected to pin A0 on the MCP23017 chip. This relay takes care of turning on/off your light.
Pressing (and releasing) a wall switch should notify openHAB, and then openHAB should change state of relay to on/off the light.
Your pin B1 should work as DIGITAL_INPUT, because it READS state of a PIN (state of wall switch). Your pin A0 should work as DIGITAL_OUTPUT
because openHAB will SET state of this PIN. So your config should look like this:
* Things:
Minimal configuration:
```
Thing mcp23017:mcp23017:chipA "MCP23017 chip A" [address=20,bus=1]
```
Configuration with default_state and pull_mode:
```
Thing mcp23017:mcp23017:chipA "MCP23017 chip A" [address=20,bus=1] {
Type output_pin : output#A0 [default_state="HIGH"]
Type output_pin : output#A1 [default_state="LOW"]
Type output_pin : output#A2 [active_low="y"]
Type output_pin : output#A2 [default_state="LOW", active_low="y"]
Type input_pin : input#B0 [pull_mode="PULL_UP"]
Type input_pin : input#B1 [pull_mode="OFF"]
}
```
* Items:
```
Switch living_room_led_switch "Living room LED switch" {channel="mcp23017:mcp23017:chipA:output#A0"}
Contact living_room_led_contact "Living room LED contact" {channel="mcp23017:mcp23017:chipA:input#B1"}
```
* Rules:
```
rule "living_room_led contact"
when
Item living_room_led_contact changed to OPEN
then
living_room_led_switch.sendCommand(if(living_room_led_switch.state != ON) ON else OFF)
end
```

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.mcp23017</artifactId>
<name>openHAB Add-ons :: Bundles :: mcp23017 Binding</name>
<dependencies>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-core</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.pi4j</groupId>
<artifactId>pi4j-gpio-extension</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.mcp23017-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-mcp23017" description="MCP23017 Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.mcp23017/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.wiringpi.GpioUtil;
/**
* The {@link GPIODataHolder} holds a reference to GpioController.
* There should be only one instance per whole system
*
* @author Anatol Ogorek - Initial contribution
*/
public class GPIODataHolder {
static {
GpioUtil.enableNonPrivilegedAccess();
}
public static final GpioController GPIO = GpioFactory.getInstance();
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link Mcp23017BindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Anatol Ogorek - Initial contribution
*/
@NonNullByDefault
public class Mcp23017BindingConstants {
public static final String BINDING_ID = "mcp23017";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_MCP23017 = new ThingTypeUID(BINDING_ID, BINDING_ID);
public static final String DEFAULT_STATE = "default_state";
public static final String ADDRESS = "address";
public static final String BUS_NUMBER = "bus_number";
public static final String PIN = "pin";
public static final String PULL_MODE = "pull_mode";
public static final String DEFAULT_PULL_MODE = "OFF";
public static final String ACTIVE_LOW = "active_low";
public static final String ACTIVE_LOW_ENABLED = "y";
public static final String CHANNEL_GROUP_INPUT = "input";
public static final String CHANNEL_GROUP_OUTPUT = "output";
public static final Set<String> SUPPORTED_CHANNEL_GROUPS = Stream.of(CHANNEL_GROUP_INPUT, CHANNEL_GROUP_OUTPUT)
.collect(Collectors.toSet());
public static final String CHANNEL_A0 = "A0";
public static final String CHANNEL_A1 = "A1";
public static final String CHANNEL_A2 = "A2";
public static final String CHANNEL_A3 = "A3";
public static final String CHANNEL_A4 = "A4";
public static final String CHANNEL_A5 = "A5";
public static final String CHANNEL_A6 = "A6";
public static final String CHANNEL_A7 = "A7";
public static final String CHANNEL_B0 = "B0";
public static final String CHANNEL_B1 = "B1";
public static final String CHANNEL_B2 = "B2";
public static final String CHANNEL_B3 = "B3";
public static final String CHANNEL_B4 = "B4";
public static final String CHANNEL_B5 = "B5";
public static final String CHANNEL_B6 = "B6";
public static final String CHANNEL_B7 = "B7";
public static final Set<String> SUPPORTED_CHANNELS = Stream
.of(CHANNEL_A0, CHANNEL_A1, CHANNEL_A2, CHANNEL_A3, CHANNEL_A4, CHANNEL_A5, CHANNEL_A6, CHANNEL_A7,
CHANNEL_B0, CHANNEL_B1, CHANNEL_B2, CHANNEL_B3, CHANNEL_B4, CHANNEL_B5, CHANNEL_B6, CHANNEL_B7)
.collect(Collectors.toSet());
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal;
import static org.openhab.binding.mcp23017.internal.Mcp23017BindingConstants.THING_TYPE_MCP23017;
import java.util.Collections;
import java.util.Set;
import org.openhab.binding.mcp23017.internal.handler.Mcp23017Handler;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link Mcp23017HandlerFactory} is responsible for creating thing
* handlers.
*
* @author Anatol Ogorek - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.mcp23017")
public class Mcp23017HandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_MCP23017);
private final Logger logger = LoggerFactory.getLogger(Mcp23017HandlerFactory.class);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
logger.debug("Trying to create handler for {}", thingTypeUID.getAsString());
if (thingTypeUID.equals(THING_TYPE_MCP23017)) {
logger.debug("Handler match for {}", thingTypeUID.getAsString());
return new Mcp23017Handler(thing);
}
logger.debug("No handler match for {}", thingTypeUID.getAsString());
return null;
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal;
import static com.pi4j.gpio.extension.mcp.MCP23017Pin.*;
import static org.openhab.binding.mcp23017.internal.Mcp23017BindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import com.pi4j.io.gpio.Pin;
/**
* @author Anatol Ogorek - Initial contribution
*/
public class PinMapper {
private static final Map<String, Pin> PIN_MAP = new HashMap<>();
static {
PIN_MAP.put(CHANNEL_A0, GPIO_A0);
PIN_MAP.put(CHANNEL_A1, GPIO_A1);
PIN_MAP.put(CHANNEL_A2, GPIO_A2);
PIN_MAP.put(CHANNEL_A3, GPIO_A3);
PIN_MAP.put(CHANNEL_A4, GPIO_A4);
PIN_MAP.put(CHANNEL_A5, GPIO_A5);
PIN_MAP.put(CHANNEL_A6, GPIO_A6);
PIN_MAP.put(CHANNEL_A7, GPIO_A7);
PIN_MAP.put(CHANNEL_B0, GPIO_B0);
PIN_MAP.put(CHANNEL_B1, GPIO_B1);
PIN_MAP.put(CHANNEL_B2, GPIO_B2);
PIN_MAP.put(CHANNEL_B3, GPIO_B3);
PIN_MAP.put(CHANNEL_B4, GPIO_B4);
PIN_MAP.put(CHANNEL_B5, GPIO_B5);
PIN_MAP.put(CHANNEL_B6, GPIO_B6);
PIN_MAP.put(CHANNEL_B7, GPIO_B7);
}
public static Pin get(String pinCode) {
return PIN_MAP.get(pinCode);
}
}

View File

@@ -0,0 +1,228 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal.handler;
import static org.openhab.binding.mcp23017.internal.Mcp23017BindingConstants.*;
import java.io.IOException;
import java.util.Objects;
import org.openhab.binding.mcp23017.internal.GPIODataHolder;
import org.openhab.binding.mcp23017.internal.PinMapper;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
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.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pi4j.gpio.extension.mcp.MCP23017GpioProvider;
import com.pi4j.io.gpio.GpioPin;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;
/**
* The {@link Mcp23017Handler} is base class for MCP23017 chip support
*
* @author Anatol Ogorek - Initial contribution
*/
public class Mcp23017Handler extends BaseThingHandler implements GpioPinListenerDigital {
private final Logger logger = LoggerFactory.getLogger(getClass());
private MCP23017GpioProvider mcpProvider;
private Integer address;
private Integer busNumber;
private Mcp23017PinStateHolder pinStateHolder;
/**
* the polling interval mcp23071 check interrupt register (optional, defaults to 50ms)
*/
private static final int POLLING_INTERVAL = 50;
public Mcp23017Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Received command: {} on channelGroup {} on channel {}", command.toFullString(),
channelUID.getGroupId(), channelUID.getIdWithoutGroup());
if (!verifyChannel(channelUID)) {
return;
}
String channelGroup = channelUID.getGroupId();
switch (channelGroup) {
case CHANNEL_GROUP_INPUT:
handleInputCommand(channelUID, command);
break;
case CHANNEL_GROUP_OUTPUT:
handleOutputCommand(channelUID, command);
default:
break;
}
}
@Override
public void initialize() {
try {
checkConfiguration();
mcpProvider = initializeMcpProvider();
pinStateHolder = new Mcp23017PinStateHolder(mcpProvider, this.thing);
updateStatus(ThingStatus.ONLINE);
} catch (IllegalArgumentException | SecurityException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"An exception occurred while adding pin. Check pin configuration. Exception: " + e.getMessage());
}
}
private boolean verifyChannel(ChannelUID channelUID) {
if (!isChannelGroupValid(channelUID) || !isChannelValid(channelUID)) {
logger.warn("Channel group or channel is invalid. Probably configuration problem");
return false;
}
return true;
}
private void handleOutputCommand(ChannelUID channelUID, Command command) {
if (command instanceof OnOffType) {
GpioPinDigitalOutput outputPin = pinStateHolder.getOutputPin(channelUID);
Configuration configuration = this.getThing().getChannel(channelUID.getId()).getConfiguration();
// invertLogic is null if not configured
String activeLowStr = Objects.toString(configuration.get(ACTIVE_LOW), null);
boolean activeLowFlag = ACTIVE_LOW_ENABLED.equalsIgnoreCase(activeLowStr);
PinState pinState = command == OnOffType.ON ^ activeLowFlag ? PinState.HIGH : PinState.LOW;
logger.debug("got output pin {} for channel {} and command {} [active_low={}, new_state={}]", outputPin,
channelUID, command, activeLowFlag, pinState);
GPIODataHolder.GPIO.setState(pinState, outputPin);
}
}
private void handleInputCommand(ChannelUID channelUID, Command command) {
logger.debug("Nothing to be done in handleCommand for contact.");
}
private boolean isChannelGroupValid(ChannelUID channelUID) {
if (!channelUID.isInGroup()) {
logger.debug("Defined channel not in group: {}", channelUID.getAsString());
return false;
}
boolean channelGroupValid = SUPPORTED_CHANNEL_GROUPS.contains(channelUID.getGroupId());
logger.debug("Defined channel in group: {}. Valid: {}", channelUID.getGroupId(), channelGroupValid);
return channelGroupValid;
}
private boolean isChannelValid(ChannelUID channelUID) {
boolean channelValid = SUPPORTED_CHANNELS.contains(channelUID.getIdWithoutGroup());
logger.debug("Is channel {} in supported channels: {}", channelUID.getIdWithoutGroup(), channelValid);
return channelValid;
}
protected void checkConfiguration() {
Configuration configuration = getConfig();
address = Integer.parseInt((configuration.get(ADDRESS)).toString(), 16);
busNumber = Integer.parseInt((configuration.get(BUS_NUMBER)).toString());
}
private MCP23017GpioProvider initializeMcpProvider() {
MCP23017GpioProvider mcp = null;
logger.debug("initializing mcp provider for busNumber {} and address {}", busNumber, address);
try {
mcp = new MCP23017GpioProvider(busNumber, address);
mcp.setPollingTime(POLLING_INTERVAL);
} catch (UnsupportedBusNumberException | IOException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Tried to access not available I2C bus: " + ex.getMessage());
}
logger.debug("got mcpProvider {}", mcp);
return mcp;
}
private GpioPinDigitalInput initializeInputPin(ChannelUID channel) {
logger.debug("initializing input pin for channel {}", channel.getAsString());
Pin pin = PinMapper.get(channel.getIdWithoutGroup());
String pullMode = DEFAULT_PULL_MODE;
if (thing.getChannel(channel.getId()) != null) {
Configuration configuration = thing.getChannel(channel.getId()).getConfiguration();
pullMode = ((String) configuration.get(PULL_MODE)) != null ? ((String) configuration.get(PULL_MODE))
: DEFAULT_PULL_MODE;
}
logger.debug("initializing pin {}, pullMode {}, mcpProvider {}", pin, pullMode, mcpProvider);
GpioPinDigitalInput input = GPIODataHolder.GPIO.provisionDigitalInputPin(mcpProvider, pin,
channel.getIdWithoutGroup(), PinPullResistance.valueOf(pullMode));
input.addListener(this);
logger.debug("Bound digital input for PIN: {}, ItemName: {}, pullMode: {}", pin, channel.getAsString(),
pullMode);
return input;
}
@Override
public void dispose() {
final Mcp23017PinStateHolder holder = pinStateHolder;
if (holder != null) {
holder.unBindGpioPins();
}
super.dispose();
}
@Override
public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
GpioPin pin = event.getPin();
OpenClosedType state = OpenClosedType.CLOSED;
if (event.getState() == PinState.LOW) {
state = OpenClosedType.OPEN;
}
ChannelUID channelForPin = pinStateHolder.getChannelForInputPin((GpioPinDigitalInput) pin);
logger.debug("updating channel {} with state {}", channelForPin, state);
updateState(channelForPin, state);
}
@Override
public void channelLinked(ChannelUID channelUID) {
synchronized (this) {
logger.debug("channel linked {}", channelUID.getAsString());
if (!verifyChannel(channelUID)) {
return;
}
String channelGroup = channelUID.getGroupId();
if (channelGroup != null && channelGroup.equals(CHANNEL_GROUP_INPUT)) {
if (pinStateHolder.getInputPin(channelUID) != null) {
return;
}
GpioPinDigitalInput inputPin = initializeInputPin(channelUID);
pinStateHolder.addInputPin(inputPin, channelUID);
}
super.channelLinked(channelUID);
}
}
}

View File

@@ -0,0 +1,101 @@
/**
* Copyright (c) 2010-2020 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.mcp23017.internal.handler;
import static org.openhab.binding.mcp23017.internal.Mcp23017BindingConstants.DEFAULT_STATE;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import org.openhab.binding.mcp23017.internal.GPIODataHolder;
import org.openhab.binding.mcp23017.internal.PinMapper;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pi4j.gpio.extension.mcp.MCP23017GpioProvider;
import com.pi4j.io.gpio.GpioPin;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinState;
/**
* The {@link Mcp23017PinStateHolder} is a class where MCP23017 PIN state is held
*
* @author Anatol Ogorek - Initial contribution
*/
public class Mcp23017PinStateHolder {
private final Logger logger = LoggerFactory.getLogger(getClass());
private Map<ChannelUID, GpioPinDigitalInput> inputPins = new HashMap<>();
private Map<ChannelUID, GpioPinDigitalOutput> outputPins = new HashMap<>();
private MCP23017GpioProvider mcpProvider;
private Thing thing;
public Mcp23017PinStateHolder(MCP23017GpioProvider mcpProvider, Thing thing) {
this.mcpProvider = mcpProvider;
this.thing = thing;
}
public GpioPin getInputPin(ChannelUID channel) {
return inputPins.get(channel);
}
public GpioPinDigitalOutput getOutputPin(ChannelUID channel) {
logger.debug("Getting output pin for channel {}", channel);
GpioPinDigitalOutput outputPin = outputPins.get(channel);
if (outputPin == null) {
outputPin = initializeOutputPin(channel);
outputPins.put(channel, outputPin);
}
return outputPin;
}
private GpioPinDigitalOutput initializeOutputPin(ChannelUID channel) {
Pin pin = PinMapper.get(channel.getIdWithoutGroup());
logger.debug("initializeOutputPin for channel {}", channel);
Configuration configuration = thing.getChannel(channel.getId()).getConfiguration();
PinState pinState = PinState.valueOf((String) configuration.get(DEFAULT_STATE));
logger.debug("initializing for pinState {}", pinState);
GpioPinDigitalOutput gpioPin = GPIODataHolder.GPIO.provisionDigitalOutputPin(mcpProvider, pin,
channel.getIdWithoutGroup(), pinState);
logger.debug("Bound digital output for PIN: {}, channel: {}, pinState: {}", pin, channel, pinState);
return gpioPin;
}
public void unBindGpioPins() {
inputPins.values().stream().forEach(gpioPin -> GPIODataHolder.GPIO.unprovisionPin(gpioPin));
inputPins.clear();
outputPins.values().stream().forEach(gpioPin -> GPIODataHolder.GPIO.unprovisionPin(gpioPin));
outputPins.clear();
}
public ChannelUID getChannelForInputPin(GpioPinDigitalInput pin) {
Optional<Entry<ChannelUID, GpioPinDigitalInput>> result = inputPins.entrySet().stream()
.filter(entry -> entry.getValue().equals(pin)).findFirst();
if (result.isPresent()) {
return result.get().getKey();
}
return null;
}
public void addInputPin(GpioPinDigitalInput pin, ChannelUID channel) {
inputPins.put(channel, pin);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="mcp23017" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>MCP23017 Binding</name>
<description>This is the binding for MCP23017 I/O expansion chips.</description>
<author>Anatol Ogorek</author>
</binding:binding>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="channel-type:input_pin:config">
<parameter name="pull_mode" type="text" required="true">
<label>PullResistor Mode</label>
<description>mcp2317 input pull resistor mode</description>
<options>
<option value="OFF">OFF</option>
<option value="PULL_UP">Internal PULL_UP</option>
</options>
<default>OFF</default>
</parameter>
</config-description>
<config-description uri="channel-type:output_pin:config">
<parameter name="default_state" type="text" required="true">
<label>Default State</label>
<description>mcp2317 pin default state (LOW, HIGH)</description>
<options>
<option value="LOW">LOW</option>
<option value="HIGH">HIGH</option>
</options>
<default>LOW</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="mcp23017"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Input Group Type -->
<channel-group-type id="inputgroup">
<label>Input Pins</label>
<description>MCP 23017 pins working in DIGITAL_INPUT mode (contact)</description>
<channels>
<channel id="A0" typeId="input_pin"/>
<channel id="A1" typeId="input_pin"/>
<channel id="A2" typeId="input_pin"/>
<channel id="A3" typeId="input_pin"/>
<channel id="A4" typeId="input_pin"/>
<channel id="A5" typeId="input_pin"/>
<channel id="A6" typeId="input_pin"/>
<channel id="A7" typeId="input_pin"/>
<channel id="B0" typeId="input_pin"/>
<channel id="B1" typeId="input_pin"/>
<channel id="B2" typeId="input_pin"/>
<channel id="B3" typeId="input_pin"/>
<channel id="B4" typeId="input_pin"/>
<channel id="B5" typeId="input_pin"/>
<channel id="B6" typeId="input_pin"/>
<channel id="B7" typeId="input_pin"/>
</channels>
</channel-group-type>
<!-- Output Group Type -->
<channel-group-type id="outputgroup">
<label>Output Pins</label>
<description>MCP 23017 pins working in DIGITAL_OUTPUT mode (switch)</description>
<channels>
<channel id="A0" typeId="output_pin"/>
<channel id="A1" typeId="output_pin"/>
<channel id="A2" typeId="output_pin"/>
<channel id="A3" typeId="output_pin"/>
<channel id="A4" typeId="output_pin"/>
<channel id="A5" typeId="output_pin"/>
<channel id="A6" typeId="output_pin"/>
<channel id="A7" typeId="output_pin"/>
<channel id="B0" typeId="output_pin"/>
<channel id="B1" typeId="output_pin"/>
<channel id="B2" typeId="output_pin"/>
<channel id="B3" typeId="output_pin"/>
<channel id="B4" typeId="output_pin"/>
<channel id="B5" typeId="output_pin"/>
<channel id="B6" typeId="output_pin"/>
<channel id="B7" typeId="output_pin"/>
</channels>
</channel-group-type>
<channel-type id="input_pin">
<item-type>Contact</item-type>
<label>Input Pin</label>
<description>channel type for MCP23017 pin in DIGITAL_INPUT mode (contact)</description>
<category>Contact</category>
<state readOnly="false"/>
<config-description-ref uri="channel-type:input_pin:config"/>
</channel-type>
<channel-type id="output_pin">
<item-type>Switch</item-type>
<label>Output Pin</label>
<description>channel type for MCP23017 pin in DIGITAL_INPUT mode (switch)</description>
<category>Switch</category>
<state readOnly="true"/>
<config-description-ref uri="channel-type:output_pin:config"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="mcp23017"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="mcp23017">
<label>MCP23017</label>
<description>Thing for mcp23017 integrated circuit</description>
<channel-groups>
<channel-group id="input" typeId="inputgroup"/>
<channel-group id="output" typeId="outputgroup"/>
</channel-groups>
<config-description>
<parameter name="address" type="integer" required="true">
<label>I2C Device Address</label>
<description>I2C Bus mcp2317 device Address in HEX</description>
<default>20</default>
</parameter>
<parameter name="bus_number" type="integer" required="true">
<label>I2C BUS Number</label>
<description>I2C Bus number (0-6)</description>
<options>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</options>
<default>1</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>