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,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.bigassfan-${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-bigassfan" description="Big Ass Fan Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.bigassfan/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,92 @@
/**
* 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.bigassfan.internal;
import java.util.Collections;
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 BigAssFanBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Mark Hilbush - Initial contribution
*/
@NonNullByDefault
public class BigAssFanBindingConstants {
public static final String BINDING_ID = "bigassfan";
// Fans communicate on this port using both UDP (discovery) and TCP (commands)
public static final int BAF_PORT = 31415;
// Commands sent to/from fan are ASCII
public static final String CHARSET = "US-ASCII";
// BigAssFan Thing Type UIDs
public static final ThingTypeUID THING_TYPE_FAN = new ThingTypeUID(BINDING_ID, "fan");
public static final ThingTypeUID THING_TYPE_LIGHT = new ThingTypeUID(BINDING_ID, "light");
public static final ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_FAN, THING_TYPE_LIGHT, THING_TYPE_CONTROLLER).collect(Collectors.toSet()));
/*
* List of Channel Ids
*/
// Fan control channels
public static final String CHANNEL_FAN_POWER = "fan-power";
public static final String CHANNEL_FAN_SPEED = "fan-speed";
public static final String CHANNEL_FAN_DIRECTION = "fan-direction";
public static final String CHANNEL_FAN_AUTO = "fan-auto";
public static final String CHANNEL_FAN_WHOOSH = "fan-whoosh";
public static final String CHANNEL_FAN_SMARTMODE = "fan-smartmode";
public static final String CHANNEL_FAN_SPEED_MIN = "fan-speed-min";
public static final String CHANNEL_FAN_SPEED_MAX = "fan-speed-max";
public static final String CHANNEL_FAN_LEARN_MINSPEED = "fan-learn-speed-min";
public static final String CHANNEL_FAN_LEARN_MAXSPEED = "fan-learn-speed-max";
public static final String CHANNEL_FAN_WINTERMODE = "fan-wintermode";
public static final String CHANNEL_FAN_SLEEP = "fan-sleep";
// Light control channels
public static final String CHANNEL_LIGHT_POWER = "light-power";
public static final String CHANNEL_LIGHT_LEVEL = "light-level";
public static final String CHANNEL_LIGHT_AUTO = "light-auto";
public static final String CHANNEL_LIGHT_SMARTER = "light-smarter";
public static final String CHANNEL_LIGHT_LEVEL_MIN = "light-level-min";
public static final String CHANNEL_LIGHT_LEVEL_MAX = "light-level-max";
public static final String CHANNEL_LIGHT_PRESENT = "light-present";
// Standalone light channels
public static final String CHANNEL_LIGHT_HUE = "light-hue";
public static final String CHANNEL_LIGHT_COLOR = "light-color";
// Miscellaneous channels
public static final String CHANNEL_MOTION = "motion";
public static final String CHANNEL_TIME = "time";
/*
* BigAssFan thing configuration parameters
*/
// IP network address of the fan
public static final String THING_PROPERTY_IP = "ipAddress";
// MAC address of the fan
public static final String THING_PROPERTY_MAC = "macAddress";
// Friendly name given to the fan
public static final String THING_PROPERTY_LABEL = "label";
}

View File

@@ -0,0 +1,79 @@
/**
* 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.bigassfan.internal;
import org.apache.commons.lang.StringUtils;
/**
* The {@link BigAssFanConfig} is responsible for storing the BigAssFan thing configuration.
*
* @author Mark Hilbush - Initial contribution
*/
public class BigAssFanConfig {
/**
* Name of the device
*/
private String label;
/**
* IP address of the device
*/
private String ipAddress;
/**
* MAC address of the device
*/
private String macAddress;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public boolean isValid() {
if (StringUtils.isBlank(label)) {
return false;
}
if (StringUtils.isBlank(ipAddress)) {
return false;
}
if (StringUtils.isBlank(macAddress)) {
return false;
}
return true;
}
@Override
public String toString() {
return "BigAssFanConfig{label=" + label + ", ipAddress=" + ipAddress + ", macAddress=" + macAddress + "}";
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.bigassfan.internal;
import static org.openhab.binding.bigassfan.internal.BigAssFanBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.bigassfan.internal.handler.BigAssFanHandler;
import org.openhab.core.net.NetworkAddressService;
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.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link BigAssFanHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Mark Hilbush - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.bigassfan")
public class BigAssFanHandlerFactory extends BaseThingHandlerFactory {
private final NetworkAddressService networkAddressService;
@Activate
public BigAssFanHandlerFactory(@Reference NetworkAddressService networkAddressService) {
this.networkAddressService = networkAddressService;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new BigAssFanHandler(thing, networkAddressService.getPrimaryIpv4HostAddress());
}
return null;
}
}

View File

@@ -0,0 +1,125 @@
/**
* 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.bigassfan.internal.discovery;
/**
* The {@link BigAssFanDevice} is responsible for storing information about a fan.
*
* @author Mark Hilbush - Initial contribution
*/
public class BigAssFanDevice {
/**
* Name of device (e.g. Master Bedroom Fan)
*/
private String label;
/**
* IP address of the device extracted from UDP packet
*/
private String ipAddress;
/**
* MAC address of the device extracted from discovery message
*/
private String macAddress;
/**
* Type of device extracted from discovery message (e.g. FAN or SWITCH)
*/
private String type;
/**
* Model of device extracted from discovery message (e.g. HSERIES)
*/
private String model;
/**
* The raw discovery message
*/
private String discoveryMessage;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDiscoveryMessage() {
return discoveryMessage;
}
public void setDiscoveryMessage(String discoveryMessage) {
this.discoveryMessage = discoveryMessage;
}
public boolean isFan() {
return type.toUpperCase().contains("FAN") ? true : false;
}
public boolean isSwitch() {
return type.toUpperCase().contains("SWITCH") ? true : false;
}
public boolean isLight() {
return type.toUpperCase().contains("LIGHT") ? true : false;
}
public void reset() {
label = "";
ipAddress = "";
macAddress = "";
type = "";
model = "";
discoveryMessage = "";
}
@Override
public String toString() {
return "BigAssFanDevice{label=" + label + ", ipAddress=" + ipAddress + ", macAddress=" + macAddress + ", model="
+ model + ", type=" + type + "}";
}
}

View File

@@ -0,0 +1,264 @@
/**
* 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.bigassfan.internal.discovery;
import static org.openhab.binding.bigassfan.internal.BigAssFanBindingConstants.*;
import java.io.IOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BigAssFanDiscoveryService} class implements a service
* for discovering the Big Ass Fans.
*
* @author Mark Hilbush - Initial contribution
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.bigassfan")
public class BigAssFanDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(BigAssFanDiscoveryService.class);
private static final boolean BACKGROUND_DISCOVERY_ENABLED = true;
private static final long BACKGROUND_DISCOVERY_DELAY = 8L;
// Our own thread pool for the long-running listener job
private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> listenerJob;
DiscoveryListener discoveryListener;
private boolean terminate;
private final Pattern announcementPattern = Pattern.compile("[(](.*);DEVICE;ID;(.*);(.*)[)]");
private Runnable listenerRunnable = () -> {
try {
listen();
} catch (RuntimeException e) {
logger.warn("Discovery listener got unexpected exception: {}", e.getMessage(), e);
}
};
// Frequency (in seconds) with which we poll for new devices
private final long POLL_FREQ = 300L;
private final long POLL_DELAY = 12L;
private ScheduledFuture<?> pollJob;
public BigAssFanDiscoveryService() {
super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return SUPPORTED_THING_TYPES_UIDS;
}
@Override
protected void activate(Map<String, Object> configProperties) {
super.activate(configProperties);
logger.trace("BigAssFan discovery service ACTIVATED");
}
@Override
protected void deactivate() {
super.deactivate();
logger.trace("BigAssFan discovery service DEACTIVATED");
}
@Override
@Modified
protected void modified(Map<String, Object> configProperties) {
super.modified(configProperties);
}
@Override
protected void startBackgroundDiscovery() {
logger.debug("Starting background discovery");
startListenerJob();
schedulePollJob();
}
@Override
protected void stopBackgroundDiscovery() {
logger.debug("Stopping background discovery");
cancelPollJob();
cancelListenerJob();
}
private void startListenerJob() {
if (listenerJob == null) {
terminate = false;
logger.debug("Starting discovery listener job in {} seconds", BACKGROUND_DISCOVERY_DELAY);
listenerJob = scheduledExecutorService.schedule(listenerRunnable, BACKGROUND_DISCOVERY_DELAY,
TimeUnit.SECONDS);
}
}
private void cancelListenerJob() {
if (listenerJob != null) {
logger.debug("Canceling discovery listener job");
listenerJob.cancel(true);
terminate = true;
listenerJob = null;
}
}
@Override
public void startScan() {
}
@Override
public void stopScan() {
}
private synchronized void listen() {
logger.info("BigAssFan discovery service is running");
try {
discoveryListener = new DiscoveryListener();
} catch (SocketException se) {
logger.warn("Got Socket exception creating multicast socket: {}", se.getMessage(), se);
return;
} catch (IOException ioe) {
logger.warn("Got IO exception creating multicast socket: {}", ioe.getMessage(), ioe);
return;
}
logger.debug("Waiting for discovery messages");
while (!terminate) {
try {
// Wait for a discovery message
processMessage(discoveryListener.waitForMessage());
} catch (SocketTimeoutException e) {
// Read on socket timed out; check for termination
continue;
} catch (IOException ioe) {
logger.warn("Got IO exception waiting for message: {}", ioe.getMessage(), ioe);
break;
}
}
discoveryListener.shutdown();
logger.debug("DiscoveryListener job is exiting");
}
private void processMessage(BigAssFanDevice device) {
if (device == null) {
return;
}
Matcher matcher = announcementPattern.matcher(device.getDiscoveryMessage());
if (matcher.find()) {
logger.debug("Match: grp1={}, grp2={}, grp(3)={}", matcher.group(1), matcher.group(2), matcher.group(3));
// Extract needed information from the discovery message
device.setLabel(matcher.group(1));
device.setMacAddress(matcher.group(2));
String[] modelParts = matcher.group(3).split(",");
switch (modelParts.length) {
case 2:
// L-Series fans
device.setType(modelParts[0]);
device.setModel(modelParts[1]);
deviceDiscovered(device);
break;
case 3:
// H-Series fans
device.setType(modelParts[0]);
device.setModel(modelParts[2]);
deviceDiscovered(device);
break;
default:
logger.info("Unable to extract device type from discovery message");
break;
}
}
}
private synchronized void deviceDiscovered(BigAssFanDevice device) {
logger.debug("Device discovered: {}", device);
ThingTypeUID thingTypeUid;
if (device.isSwitch()) {
logger.debug("Add controller with IP={}, MAC={}, MODEL={}", device.getIpAddress(), device.getMacAddress(),
device.getModel());
thingTypeUid = THING_TYPE_CONTROLLER;
} else if (device.isFan()) {
logger.debug("Add fan with IP={}, MAC={}, MODEL={}", device.getIpAddress(), device.getMacAddress(),
device.getModel());
thingTypeUid = THING_TYPE_FAN;
} else if (device.isLight()) {
logger.debug("Add light with IP={}, MAC={}, MODEL={}", device.getIpAddress(), device.getMacAddress(),
device.getModel());
thingTypeUid = THING_TYPE_LIGHT;
} else {
logger.info("Discovered unknown device type {} at IP={}", device.getModel(), device.getIpAddress());
return;
}
// We got a valid discovery message. Process it as a potential new thing
String serialNumber = device.getMacAddress().replace(":", "");
Map<String, Object> properties = new HashMap<>();
properties.put(THING_PROPERTY_MAC, device.getMacAddress());
properties.put(THING_PROPERTY_IP, device.getIpAddress());
properties.put(THING_PROPERTY_LABEL, device.getLabel());
properties.put(Thing.PROPERTY_SERIAL_NUMBER, serialNumber);
properties.put(Thing.PROPERTY_MODEL_ID, device.getModel());
properties.put(Thing.PROPERTY_VENDOR, "Haiku");
ThingUID uid = new ThingUID(thingTypeUid, serialNumber);
logger.debug("Creating discovery result for UID={}, IP={}", uid, device.getIpAddress());
thingDiscovered(
DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(device.getLabel()).build());
}
private void schedulePollJob() {
logger.debug("Scheduling discovery poll job to run every {} seconds starting in {} sec", POLL_FREQ, POLL_DELAY);
cancelPollJob();
pollJob = scheduler.scheduleWithFixedDelay(() -> {
try {
discoveryListener.pollForDevices();
} catch (RuntimeException e) {
logger.warn("Poll job got unexpected exception: {}", e.getMessage(), e);
}
}, POLL_DELAY, POLL_FREQ, TimeUnit.SECONDS);
}
private void cancelPollJob() {
if (pollJob != null) {
logger.debug("Canceling poll job");
pollJob.cancel(true);
pollJob = null;
}
}
}

View File

@@ -0,0 +1,108 @@
/**
* 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.bigassfan.internal.discovery;
import static org.openhab.binding.bigassfan.internal.BigAssFanBindingConstants.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DiscoveryListener} is responsible for listening on the UDP socket for fan discovery messages.
*
* @author Mark Hilbush - Initial contribution
*/
public class DiscoveryListener {
private final Logger logger = LoggerFactory.getLogger(DiscoveryListener.class);
private final String BCAST_ADDRESS = "255.255.255.255";
private final int SOCKET_RECEIVE_TIMEOUT = 500;
private final String POLL_MESSAGE = "<ALL;DEVICE;ID;GET>";
DatagramSocket dSocket;
DatagramPacket rcvPacket;
byte[] rcvBuffer;
InetAddress bcastAddress;
byte[] bcastBuffer;
DatagramPacket bcastPacket;
BigAssFanDevice device;
public DiscoveryListener() throws IOException, SocketException {
logger.debug("DiscoveryListener opening UDP broadcast socket");
dSocket = null;
device = new BigAssFanDevice();
try {
// Create a socket on the UDP port and get send & receive buffers
dSocket = new DatagramSocket(BAF_PORT);
dSocket.setSoTimeout(SOCKET_RECEIVE_TIMEOUT);
dSocket.setBroadcast(true);
rcvBuffer = new byte[256];
rcvPacket = new DatagramPacket(rcvBuffer, rcvBuffer.length);
bcastAddress = InetAddress.getByName(BCAST_ADDRESS);
bcastBuffer = POLL_MESSAGE.getBytes(CHARSET);
bcastPacket = new DatagramPacket(bcastBuffer, bcastBuffer.length, bcastAddress, BAF_PORT);
} catch (UnknownHostException uhe) {
logger.warn("UnknownHostException sending poll request for fans: {}", uhe.getMessage(), uhe);
} catch (UnsupportedEncodingException e) {
logger.warn("Unable to convert buffer to string using {} charset", CHARSET, e);
}
}
public BigAssFanDevice waitForMessage() throws IOException, SocketTimeoutException {
// Wait to receive a packet
rcvPacket.setLength(rcvBuffer.length);
dSocket.receive(rcvPacket);
// Process the received packet
device.reset();
device.setIpAddress(rcvPacket.getAddress().getHostAddress());
String message = (new String(rcvBuffer, 0, rcvPacket.getLength()));
device.setDiscoveryMessage(message);
logger.debug("RECEIVED packet of length {} from {}: {}", message.length(), device.getIpAddress(), message);
return device;
}
public void pollForDevices() {
if (dSocket == null) {
logger.debug("Socket is null in discoveryListener.pollForDevices()");
return;
}
logger.debug("Sending poll request for fans: {}", POLL_MESSAGE);
try {
dSocket.send(bcastPacket);
} catch (IOException ioe) {
logger.warn("IOException sending poll request for fans: {}", ioe.getMessage(), ioe);
}
}
public void shutdown() {
logger.debug("DiscoveryListener closing socket");
if (dSocket != null) {
dSocket.close();
dSocket = null;
}
}
}

View File

@@ -0,0 +1,87 @@
/**
* 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.bigassfan.internal.utils;
import org.openhab.core.library.types.PercentType;
/**
* The {@link BigAssFanConverter} is responsible for converting between
* Dimmer values and values used for fan speed, light brightness, and
* light color temperature.
*
* @author Mark Hilbush - Initial contribution
*/
public class BigAssFanConverter {
/*
* Conversion factor for fan range (0-7) to dimmer range (0-100).
*/
private static final double SPEED_CONVERSION_FACTOR = 14.2857;
/*
* Conversion factor for light range (0-16) to dimmer range (0-100).
*/
private static final double BRIGHTNESS_CONVERSION_FACTOR = 6.25;
/*
* Conversion factor for hue range (2200-5000) to dimmer range (0-100).
*/
private static final double HUE_CONVERSION_FACTOR = 28.0;
/*
* Dimmer item will produce PercentType value, which is 0-100
* Convert that value to what the fan expects, which is 0-7
*/
public static String percentToSpeed(PercentType command) {
return String.valueOf((int) Math.round(command.doubleValue() / SPEED_CONVERSION_FACTOR));
}
/*
* Fan will supply fan speed value in range of 0-7
* Convert that value to a PercentType in range 0-100, which is what Dimmer item expects
*/
public static PercentType speedToPercent(String speed) {
return new PercentType((int) Math.round(Integer.parseInt(speed) * SPEED_CONVERSION_FACTOR));
}
/*
* Dimmer item will produce PercentType value, which is 0-100
* Convert that value to what the light expects, which is 0-16
*/
public static String percentToLevel(PercentType command) {
return String.valueOf((int) Math.round(command.doubleValue() / BRIGHTNESS_CONVERSION_FACTOR));
}
/*
* Light will supply brightness value in range of 0-16
* Convert that value to a PercentType in range 0-100, which is what Dimmer item expects
*/
public static PercentType levelToPercent(String level) {
return new PercentType((int) Math.round(Integer.parseInt(level) * BRIGHTNESS_CONVERSION_FACTOR));
}
/*
* Dimmer item will produce PercentType value, which is 0-100
* Convert that value to what the light expects, which is 2200-5000
*/
public static String percentToHue(PercentType command) {
return String.valueOf(2200 + (int) Math.round(command.doubleValue() * HUE_CONVERSION_FACTOR));
}
/*
* Light will supply hue value in range of 2200-5000
* Convert that value to a PercentType in range 0-100, which is what Dimmer item expects
*/
public static PercentType hueToPercent(String hue) {
return new PercentType((int) Math.round((Integer.parseInt(hue) - 2200) / HUE_CONVERSION_FACTOR));
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="bigassfan" 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>BigAssFan Binding</name>
<description>This is the binding for BigAssFan.</description>
<author>Mark Hilbush</author>
</binding:binding>

View File

@@ -0,0 +1,23 @@
<?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="thing-type:bigassfan:device">
<parameter name="label" type="text" required="true">
<label>Name of Device</label>
<description>Enter the name you've given to the device</description>
</parameter>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Enter the IP address of the device</description>
<context>network-address</context>
</parameter>
<parameter name="macAddress" type="text" required="true">
<label>MAC Address</label>
<description>Enter the MAC address of the device</description>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,239 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="bigassfan"
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 for BigAssFan fan -->
<thing-type id="fan">
<label>BigAssFan</label>
<description>Big Ass Fan</description>
<channels>
<!-- Channels related to fan functions -->
<channel id="fan-power" typeId="fan-power"/>
<channel id="fan-speed" typeId="fan-speed"/>
<channel id="fan-direction" typeId="fan-direction"></channel>
<channel id="fan-auto" typeId="fan-auto"/>
<channel id="fan-whoosh" typeId="fan-whoosh"/>
<channel id="fan-smartmode" typeId="fan-smartmode"/>
<channel id="fan-learn-speed-min" typeId="fan-learn-speed-min"/>
<channel id="fan-learn-speed-max" typeId="fan-learn-speed-max"/>
<channel id="fan-speed-min" typeId="fan-speed-min"/>
<channel id="fan-speed-max" typeId="fan-speed-max"/>
<channel id="fan-wintermode" typeId="fan-wintermode"/>
<channel id="fan-sleep" typeId="fan-sleep"/>
<!-- Channels related to light functions -->
<channel id="light-power" typeId="light-power"/>
<channel id="light-level" typeId="light-level"/>
<channel id="light-auto" typeId="light-auto"/>
<channel id="light-smarter" typeId="light-smarter"/>
<channel id="light-level-min" typeId="light-level-min"/>
<channel id="light-level-max" typeId="light-level-max"/>
<channel id="light-present" typeId="light-present"/>
<!-- Channels related to motion sensor -->
<channel id="motion" typeId="motion"/>
<!-- Miscellaneous channels -->
<channel id="time" typeId="time"/>
</channels>
<config-description-ref uri="thing-type:bigassfan:device"/>
</thing-type>
<!-- Thing Type for BigAssFan light -->
<thing-type id="light">
<label>Light</label>
<description>Light</description>
<channels>
<!-- Channels related to light functions -->
<channel id="light-power" typeId="light-power"/>
<channel id="light-level" typeId="light-level"/>
<channel id="light-hue" typeId="light-hue"/>
<channel id="light-present" typeId="light-present"/>
<channel id="light-color" typeId="light-color"/>
<!-- Channels related to motion sensor -->
<channel id="motion" typeId="motion"/>
<!-- Miscellaneous channels -->
<channel id="time" typeId="time"/>
</channels>
<config-description-ref uri="thing-type:bigassfan:device"/>
</thing-type>
<!-- Thing Type for BigAssFan controller -->
<thing-type id="controller">
<label>Controller</label>
<description>Wall controller for Big Ass Fan</description>
<channels>
<channel id="motion" typeId="motion"/>
<channel id="time" typeId="time"/>
</channels>
<config-description-ref uri="thing-type:bigassfan:device"/>
</thing-type>
<!-- Channel types -->
<channel-type id="fan-power">
<item-type>Switch</item-type>
<label>Fan Power</label>
<description>Turn the fan on and off</description>
<category>Switch</category>
</channel-type>
<channel-type id="fan-speed">
<item-type>Dimmer</item-type>
<label>Fan Speed</label>
<description>Control the speed of the fan</description>
</channel-type>
<channel-type id="fan-direction">
<item-type>String</item-type>
<label>Fan Direction</label>
<description>Forward or reverse</description>
<state readOnly="true">
<options>
<option value="FWD">Forward</option>
<option value="REV">Reverse</option>
</options>
</state>
</channel-type>
<channel-type id="fan-auto">
<item-type>Switch</item-type>
<label>Fan Auto Mode</label>
<description>Enable or disable fan auto mode</description>
<category>Switch</category>
</channel-type>
<channel-type id="fan-whoosh">
<item-type>Switch</item-type>
<label>Fan Whoosh Mode</label>
<description>Enable or disable fan whoosh mode</description>
<category>Switch</category>
</channel-type>
<channel-type id="fan-smartmode">
<item-type>String</item-type>
<label>Fan Smartmode</label>
<description>Set Smartmode to OFF, COOLING, or HEATING</description>
<state>
<options>
<option value="OFF">OFF</option>
<option value="COOLING">COOLING</option>
<option value="HEATING">HEATING</option>
</options>
</state>
</channel-type>
<channel-type id="fan-learn-speed-min">
<item-type>Dimmer</item-type>
<label>Minimum Fan Speed</label>
<description>Set the minimum fan speed when in Smart Cooling mode</description>
</channel-type>
<channel-type id="fan-learn-speed-max">
<item-type>Dimmer</item-type>
<label>Maximum Fan Speed</label>
<description>Set the maximum fan speed when in Smart Cooling mode</description>
</channel-type>
<channel-type id="fan-speed-min">
<item-type>Dimmer</item-type>
<label>Minimum Fan Speed</label>
<description>Set the minimum fan speed</description>
</channel-type>
<channel-type id="fan-speed-max">
<item-type>Dimmer</item-type>
<label>Maximum Fan Speed</label>
<description>Set the maximum fan speed</description>
</channel-type>
<channel-type id="fan-wintermode">
<item-type>Switch</item-type>
<label>Fan Winter Mode</label>
<description>Enable or disable fan winter mode</description>
<category>Switch</category>
</channel-type>
<channel-type id="fan-sleep">
<item-type>Switch</item-type>
<label>Sleep Mode</label>
<description>Enable or disable fan sleep mode</description>
<category>Switch</category>
</channel-type>
<channel-type id="light-power">
<item-type>Switch</item-type>
<label>Light Power</label>
<description>Turn the fan's light on and off</description>
<category>Switch</category>
</channel-type>
<channel-type id="light-level">
<item-type>Dimmer</item-type>
<label>Light Brightness</label>
<description>The brightness level of the fan's light</description>
<category>DimmableLight</category>
</channel-type>
<channel-type id="light-auto">
<item-type>Switch</item-type>
<label>Light Auto Mode</label>
<description>Enable or disable light auto mode</description>
<category>Switch</category>
</channel-type>
<channel-type id="light-smarter">
<item-type>Switch</item-type>
<label>Smarter Lighting</label>
<description>Enable or disable Smarter Lighting</description>
<category>Switch</category>
</channel-type>
<channel-type id="light-level-min">
<item-type>Dimmer</item-type>
<label>Minimum Brightness</label>
<description>Set the minimum brightness level when using Smarter Lighting</description>
</channel-type>
<channel-type id="light-level-max">
<item-type>Dimmer</item-type>
<label>Maximum Brightness</label>
<description>Set the maximum brightness level when using Smarter Lighting</description>
</channel-type>
<channel-type id="light-hue">
<item-type>Dimmer</item-type>
<label>Hue</label>
<description>Set the hue of the light</description>
</channel-type>
<channel-type id="light-present">
<item-type>String</item-type>
<label>Light Present</label>
<description>Fan has the integrated light installed</description>
<state readOnly="true">
<options>
<option value="PRESENT">Present</option>
<option value="NOTPRESENT">Not Present</option>
</options>
</state>
</channel-type>
<channel-type id="light-color">
<item-type>String</item-type>
<label>Light Color</label>
<description>Light allows hue to be adjusted</description>
<state readOnly="true">
<options>
<option value="COLOR">Color</option>
<option value="NOCOLOR">No Color</option>
</options>
</state>
</channel-type>
<channel-type id="motion">
<item-type>Switch</item-type>
<label>Motion Sensor</label>
<description>The fan's motion sensor has detected motion</description>
<state readOnly="true">
<options>
<option value="ON">Triggered</option>
<option value="OFF">Untriggered</option>
</options>
</state>
</channel-type>
<channel-type id="time" advanced="true">
<item-type>DateTime</item-type>
<label>Time</label>
<description>Time reported by the fan</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>