/**
* 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.action.satel.internal;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.openhab.binding.satel.command.ReadDeviceInfoCommand;
import org.openhab.binding.satel.command.ReadDeviceInfoCommand.DeviceType;
import org.openhab.binding.satel.command.ReadEventCommand;
import org.openhab.binding.satel.command.ReadEventCommand.EventClass;
import org.openhab.binding.satel.command.ReadEventDescCommand;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.scriptengine.action.ActionDoc;
import org.openhab.core.scriptengine.action.ParamDoc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class contains the methods that are made available in scripts and rules
* for Satel.
*
* @author Krzysztof Goworek
* @since 1.9.0
*/
public class Satel {
private static final Logger logger = LoggerFactory.getLogger(Satel.class);
private static Map<String, EventDescription> eventDescriptions = new ConcurrentHashMap<String, EventDescription>();
/**
* Checks current connection status to the communication module.
*
* @return <code>true</code> if connection is established
*/
@ActionDoc(text = "Check current connection status to Satel communication module", returns = "<code>true</code>, if connected and <code>false</code> otherwise.")
public static boolean satelIsConnected() {
if (!SatelActionService.isProperlyConfigured) {
logger.debug("Satel action is not yet configured - execution aborted!");
return false;
}
if (SatelActionService.satelCommModule == null) {
logger.debug("Satel communication module not available - execution aborted!");
return false;
}
if (!SatelActionService.satelCommModule.isConnected()) {
logger.debug("Satel communication module is not connected");
return false;
}
return true;
}
/**
* Read event log record from the alarm system for given index.
* For the most recent record pass <code>-1</code> as index,
* next records can be retrieved by using next index value in the record data (the last field in a record).
*
* Fields in the record:
* <ol>
* <li>timestamp - {@link DateTimeType}</li>
* <li>partition - String</li>
* <li>event class - {@link EventClass}</li>
* <li>event code - Integer}</li>
* <li>state restoration flag - Boolean</li>
* <li>event description - String</li>
* <li>kind of description - Integer</li>
* <li>source - Integer</li>
* <li>object - Integer</li>
* <li>user control number - Integer</li>
* <li>next record index - Integer</li>
* <li>current record index - Integer</li>
* </ol>
*
* <p>
* The details about each field meaning can be found in protocol documentation.
* </p>
*
* @param eventIndex event log record index to read
* @return event as array of objects
*/
@ActionDoc(text = "Returns record from the event log for given index", returns = "Array of values: timestamp, partition, event class, event code, restore, event description, kind og description, source, object, user control object, next event index, current event index")
public static Object[] satelReadEvent(
@ParamDoc(name = "eventIndex", text = "index of event to read, -1 for the most recent") int eventIndex) {
if (!satelIsConnected()) {
logger.warn("Not connected to communication module or Satel binding not available.");
return null;
}
ReadEventCommand cmd = new ReadEventCommand(eventIndex);
if (!SatelActionService.satelCommModule.sendCommand(cmd)) {
logger.error("Unable to read record for given index: {}", eventIndex);
return null;
} else if (cmd.isEmpty()) {
logger.warn("No record under given index: {}", eventIndex);
return null;
} else {
EventDescription desc = getEventDescription(cmd.getEventCode(), cmd.isRestore());
return new Object[] { new DateTimeType(cmd.getTimestamp()), cmd.getPartition(), cmd.getEventClass(),
cmd.getEventCode(), cmd.isRestore(), desc.eventText, desc.descKind, cmd.getSource(),
cmd.getObject(), cmd.getUserControlNumber(), cmd.getNextIndex(), cmd.getCurrentIndex() };
}
}
/**
* Reads name of alarm system's device.
* Device types:
* <ul>
* <li>PARTITION</li>
* <li>ZONE</li>
* <li>USER</li>
* <li>EXPANDER</li>
* <li>LCD</li>
* <li>OUTPUT</li>
* <li>TIMER</li>
* <li>TELEPHONE</li>
* <li>OBJECT</li>
* </ul>
*
* @param deviceType type of the device
* @param deviceNumber number of the device
* @return string representing device's name or <code>null</code> if device is not present or an error occurred
*/
@ActionDoc(text = "Returns name of a device.")
public static String satelReadDeviceName(
@ParamDoc(name = "deviceType", text = "type of the device, one of: PARTITION, ZONE, USER, EXPANDER, LCD, OUTPUT, TIMER, TELEPHONE, OBJECT") String deviceType,
@ParamDoc(name = "deviceNumber", text = "number of the device to read") int deviceNumber) {
if (!satelIsConnected()) {
logger.warn("Not connected to communication module or Satel binding not available.");
return null;
}
DeviceType devType;
try {
devType = DeviceType.valueOf(deviceType.toUpperCase());
} catch (Exception e) {
logger.warn("Invalid device type given: {}", deviceType);
return null;
}
ReadDeviceInfoCommand cmd = new ReadDeviceInfoCommand(devType, deviceNumber);
if (!SatelActionService.satelCommModule.sendCommand(cmd)) {
logger.warn("Unable to read device info: {}, {}", deviceType, deviceNumber);
return null;
}
try {
return cmd.getName(SatelActionService.satelCommModule.getTextEncoding());
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding: {}", SatelActionService.satelCommModule.getTextEncoding());
return null;
}
}
@ActionDoc(text = "Overrides configured user code. It will be used for all operations that require authorization.")
public static void satelSetUserCode(@ParamDoc(name = "userCode", text = "user code to set") String userCode) {
if (SatelActionService.satelCommModule == null) {
logger.debug("Satel communication module not available - execution aborted!");
} else {
SatelActionService.satelCommModule.setUserCode(userCode);
}
}
@ActionDoc(text = "Reverts user code to the one configured in settings.")
public static void satelResetUserCode() {
if (SatelActionService.satelCommModule == null) {
logger.debug("Satel communication module not available - execution aborted!");
} else {
SatelActionService.satelCommModule.resetUserCode();
}
}
private static class EventDescription {
String eventText;
int descKind;
EventDescription(String eventText, int descKind) {
this.eventText = eventText;
this.descKind = descKind;
}
}
private static EventDescription getEventDescription(int eventCode, boolean restore) {
String mapKey = String.format("%d_%b", eventCode, restore);
EventDescription eventDesc = eventDescriptions.get(mapKey);
if (eventDesc != null) {
return eventDesc;
}
ReadEventDescCommand cmd = new ReadEventDescCommand(eventCode, restore, true);
if (!SatelActionService.satelCommModule.sendCommand(cmd)) {
logger.error("Unable to read event description: {}, {}", eventCode, restore);
return new EventDescription("Unable to read", 0);
} else {
try {
eventDesc = new EventDescription(cmd.getText(SatelActionService.satelCommModule.getTextEncoding()),
cmd.getKind());
eventDescriptions.put(mapKey, eventDesc);
return eventDesc;
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding: {}", SatelActionService.satelCommModule.getTextEncoding());
return new EventDescription("Unsupported encoding", 0);
}
}
}
}