/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.souliss.internal;
import java.io.IOException;
import java.util.Dictionary;
import java.util.Enumeration;
import org.openhab.binding.souliss.SoulissBindingProvider;
import org.openhab.binding.souliss.internal.network.typicals.Constants;
import org.openhab.binding.souliss.internal.network.typicals.Monitor;
import org.openhab.binding.souliss.internal.network.typicals.RefreshHEALTY;
import org.openhab.binding.souliss.internal.network.typicals.RefreshSUBSCRIPTION;
import org.openhab.binding.souliss.internal.network.typicals.SoulissGenericTypical;
import org.openhab.binding.souliss.internal.network.typicals.SoulissNetworkParameter;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT11;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT12;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT14;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT16;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT18;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT19;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT21;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT22;
import org.openhab.binding.souliss.internal.network.typicals.SoulissT31;
import org.openhab.binding.souliss.internal.network.typicals.StateTraslator;
import org.openhab.binding.souliss.internal.network.udp.HalfFloatUtils;
import org.openhab.binding.souliss.internal.network.udp.SendDispatcher;
import org.openhab.binding.souliss.internal.network.udp.UDPServerThread;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.Command;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class load from openhab.cfg all configuration parameters
* Receive Command from OpenHAB, translate and send it to Souliss
*
* @author Tonino Fazio
* @since 1.7.0
*/
public class SoulissBinding<E> extends AbstractActiveBinding<SoulissBindingProvider>implements ManagedService {
private static Logger logger = LoggerFactory.getLogger(SoulissBinding.class);
Monitor mon;
SendDispatcher sendDisp;
UDPServerThread UDP_Server;
RefreshSUBSCRIPTION susbcription;
RefreshHEALTY healty;
private static final int OH_REFRESH_TIME = 50;
long start_time = System.currentTimeMillis();
Timers timers = new Timers(4);
protected void addBindingProvider(SoulissBindingProvider bindingProvider) {
super.addBindingProvider(bindingProvider);
}
protected void removeBindingProvider(SoulissBindingProvider bindingProvider) {
super.removeBindingProvider(bindingProvider);
}
/**
* Read parameters from cfg file
*
* @author Tonino Fazio
* @since 1.7.0
*/
@Override
public void updated(Dictionary<String, ?> config) throws ConfigurationException {
if (config != null) {
Enumeration<String> enumConfig = config.keys();
while (enumConfig.hasMoreElements()) {
String sName = enumConfig.nextElement();
logger.info("PARAMETER: {} = {}", sName, config.get(sName));
if (sName.equals("IP_LAN")) {
SoulissNetworkParameter.IPAddressOnLAN = (String) config.get(sName);
} else if (sName.equals("REFRESH_DBSTRUCT_TIME")) {
SoulissNetworkParameter.REFRESH_DBSTRUCT_TIME = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("REFRESH_SUBSCRIPTION_TIME")) {
SoulissNetworkParameter.REFRESH_SUBSCRIPTION_TIME = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("REFRESH_HEALTY_TIME")) {
SoulissNetworkParameter.REFRESH_HEALTY_TIME = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("REFRESH_MONITOR_TIME")) {
SoulissNetworkParameter.REFRESH_MONITOR_TIME = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("SEND_DELAY")) {
SoulissNetworkParameter.SEND_DELAY = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("SEND_MIN_DELAY")) {
SoulissNetworkParameter.SEND_MIN_DELAY = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("SECURE_SEND_TIMEOUT_TO_REQUEUE")) {
SoulissNetworkParameter.SECURE_SEND_TIMEOUT_TO_REQUEUE = Long.parseLong((String) config.get(sName));
} else if (sName.equals("SECURE_SEND_TIMEOUT_TO_REMOVE_PACKET")) {
SoulissNetworkParameter.SECURE_SEND_TIMEOUT_TO_REMOVE_PACKET = Long
.parseLong((String) config.get(sName));
} else if (sName.equals("USER_INDEX")) {
SoulissNetworkParameter.UserIndex = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("NODE_INDEX")) {
SoulissNetworkParameter.NodeIndex = Integer.parseInt((String) config.get(sName));
} else if (sName.equals("SERVERPORT")) {
if (config.get(sName).equals("")) {
SoulissNetworkParameter.serverPort = null;
} else {
SoulissNetworkParameter.serverPort = Integer.parseInt((String) config.get(sName));
}
}
}
}
initialize();
setProperlyConfigured(true);
}
@Override
/**
* Get the souliss's typical from the hash table and send a command
*
* @author Tonino Fazio
* @since 1.7.0
*/
public void receiveCommand(String itemName, Command command) {
// Get the typical defined in the hash table
SoulissGenericTypical T = SoulissGenericBindingProvider.SoulissTypicalsRecipients.getTypicalFromItem(itemName);
logger.info("receiveCommand - {} = {} - Typical: 0x{}", itemName, command, Integer.toHexString(T.getType()));
switch (T.getType()) {
case Constants.Souliss_T11:
SoulissT11 T11 = (SoulissT11) T;
T11.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
break;
case Constants.Souliss_T12:
SoulissT12 T12 = (SoulissT12) T;
if (itemName.equals(T12.getsItemNameAutoModeValue())) {
T12.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T12_Use_Of_Slot_AUTOMODE + "_" + command.toString()));
} else if (itemName.equals(T12.getsItemNameSwitchValue())) {
T12.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T12_Use_Of_Slot_SWITCH + "_" + command.toString()));
}
break;
case Constants.Souliss_T14:
SoulissT14 T14 = (SoulissT14) T;
T14.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
break;
case Constants.Souliss_T18:
SoulissT18 T18 = (SoulissT18) T;
T18.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
break;
case Constants.Souliss_T16:
SoulissT16 T16 = (SoulissT16) T;
String cmd = command.getClass().getSimpleName();
if (cmd.equals(Constants.Openhab_RGB_TYPE)) {
String HSB[] = command.toString().split(",");
short RGB[] = HSBtoRGB(Float.parseFloat(HSB[0]), Float.parseFloat(HSB[1]),
Float.parseFloat(HSB[2]));
T16.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.getClass().getSimpleName()),
RGB[0], RGB[1], RGB[2]);
} else {
T16.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
}
break;
case Constants.Souliss_T19:
SoulissT19 T19 = (SoulissT19) T;
if (command instanceof PercentType) {
int percentToShort = (((PercentType) command).shortValue() * 254 / 100);
T19.commandSEND(Constants.Souliss_T1n_Set, Short.parseShort(String.valueOf(percentToShort)));
} else if (command instanceof DecimalType) {
int decimalToShort = (((DecimalType) command).shortValue() * 254 / 100);
T19.commandSEND(Constants.Souliss_T1n_Set, Short.parseShort(String.valueOf(decimalToShort)));
} else {
T19.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
}
break;
case Constants.Souliss_T21:
SoulissT21 T21 = (SoulissT21) T;
T21.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
break;
case Constants.Souliss_T22:
SoulissT22 T22 = (SoulissT22) T;
T22.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(), command.toString()));
break;
case Constants.Souliss_T31:
SoulissT31 T31 = (SoulissT31) T;
// Setpoint
if (itemName.equals(T31.getsItemNameSetpointValue())) {
if (command instanceof DecimalType) {
int uu = HalfFloatUtils.fromFloat(((DecimalType) command).floatValue());
byte B2 = (byte) (uu >> 8);
byte B1 = (byte) uu;
// setpoint command
T31.CommandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_SETPOINT_COMMAND), B1, B2);
}
}
// Set As Measured
else if (itemName.equals(T31.setAsMeasured.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_SETASMEASURED + "_" + command.toString()));
} else if (itemName.equals(T31.heatingCoolingModeValue.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_HEATING_COOLING + "_" + command.toString()));
} else if (itemName.equals(T31.fanAutoMode.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_FANAUTOMODE + "_" + command.toString()));
} else if (itemName.equals(T31.fanOff.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_FANOFF + "_" + command.toString()));
} else if (itemName.equals(T31.fanLow.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_FANLOW + "_" + command.toString()));
} else if (itemName.equals(T31.fanMed.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_FANMED + "_" + command.toString()));
} else if (itemName.equals(T31.fanHigh.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_FANHIGH + "_" + command.toString()));
} else if (itemName.equals(T31.power.getName())) {
T31.commandSEND(StateTraslator.commandsOHtoSOULISS(T.getType(),
Constants.Souliss_T31_Use_Of_Slot_POWER + "_" + command.toString()));
}
break;
default:
logger.debug("Typical Unknown");
}
}
/**
* Convert color format from HSB to RGB
*
* @param H
* @param S
* @param B
* @return short RGBList[] contain RGB components
*/
private short[] HSBtoRGB(Float H, Float S, Float B) {
short RGBList[] = hsvToRgb(H, S, B);
return RGBList;
}
public short[] hsvToRgb(float H, float S, float V) {
float R, G, B;
H /= 360f;
S /= 100f;
V /= 100f;
if (S == 0) {
R = V * 255;
G = V * 255;
B = V * 255;
} else {
float var_h = H * 6;
if (var_h == 6) {
var_h = 0; // H must be < 1
}
int var_i = (int) Math.floor(var_h); // Or ... var_i =
// floor( var_h )
float var_1 = V * (1 - S);
float var_2 = V * (1 - S * (var_h - var_i));
float var_3 = V * (1 - S * (1 - (var_h - var_i)));
float var_r;
float var_g;
float var_b;
if (var_i == 0) {
var_r = V;
var_g = var_3;
var_b = var_1;
} else if (var_i == 1) {
var_r = var_2;
var_g = V;
var_b = var_1;
} else if (var_i == 2) {
var_r = var_1;
var_g = V;
var_b = var_3;
} else if (var_i == 3) {
var_r = var_1;
var_g = var_2;
var_b = V;
} else if (var_i == 4) {
var_r = var_3;
var_g = var_1;
var_b = V;
} else {
var_r = V;
var_g = var_1;
var_b = var_2;
}
R = var_r * 255; // RGB results from 0 to 255
G = var_g * 255;
B = var_b * 255;
}
short RGBList[] = { (short) R, (short) G, (short) B };
return RGBList;
}
/**
* Start threads and prepare other functionality (used with Binding.execute()
*/
private void initialize() {
logger.info("START");
try {
// Start listening on the UDP socket
UDPServerThread UDP_Server = null;
UDP_Server = new UDPServerThread(SoulissGenericBindingProvider.SoulissTypicalsRecipients);
UDP_Server.start();
// Start the thread that send back to openHAB the souliss'
// typical values
mon = new Monitor(SoulissGenericBindingProvider.SoulissTypicalsRecipients,
SoulissNetworkParameter.REFRESH_MONITOR_TIME, eventPublisher);
// Start the thread that send network packets to the Souliss
// network
sendDisp = new SendDispatcher(SoulissGenericBindingProvider.SoulissTypicalsRecipients,
SoulissNetworkParameter.SEND_DELAY, SoulissNetworkParameter.SEND_MIN_DELAY);
// Start the thread that subscribe data from the Souliss network
susbcription = new RefreshSUBSCRIPTION(UDP_Server.getSocket(), SoulissNetworkParameter.IPAddressOnLAN);
healty = new RefreshHEALTY(UDP_Server.getSocket(), SoulissNetworkParameter.IPAddressOnLAN);
} catch (IOException e) {
logger.error(e.getMessage());
}
}
@Override
protected void execute() {
if (timers.checkTime(0, SoulissNetworkParameter.REFRESH_MONITOR_TIME)) {
mon.tick();
timers.resetTime(0);
}
if (timers.checkTime(1, SoulissNetworkParameter.SEND_MIN_DELAY)) {
sendDisp.tick();
timers.resetTime(1);
}
if (timers.checkTime(2, SoulissNetworkParameter.REFRESH_SUBSCRIPTION_TIME)) {
susbcription.tick();
timers.resetTime(2);
}
if (timers.checkTime(3, SoulissNetworkParameter.REFRESH_HEALTY_TIME)) {
healty.tick();
timers.resetTime(3);
}
}
// timer for execution of code in Binding.execute()
private class Timers {
long[] timersArray;
public Timers(int nrTimers) {
timersArray = new long[nrTimers];
}
private boolean checkTime(int iNrTimer, long t) {
// return true when code can be executed
return (System.currentTimeMillis() - timersArray[iNrTimer] > t);
}
private void resetTime(int iNrTimer) {
timersArray[iNrTimer] = System.currentTimeMillis();
}
}
@Override
protected long getRefreshInterval() {
return OH_REFRESH_TIME;
}
@Override
protected String getName() {
return "Souliss Refresh Service";
}
@Override
public void bindingChanged(BindingProvider provider, String itemName) {
// TODO Auto-generated method stub
super.bindingChanged(provider, itemName);
this.addBindingProvider(provider);
}
}