Skip to content

Commit

Permalink
[tacmi] Support time values via a DateTime channel
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Niessner <[email protected]>
  • Loading branch information
marvkis committed Sep 28, 2024
1 parent 3097d4e commit 1f6c2c6
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
Expand All @@ -33,6 +37,7 @@
import org.openhab.binding.tacmi.internal.TACmiBindingConstants;
import org.openhab.binding.tacmi.internal.TACmiChannelTypeProvider;
import org.openhab.binding.tacmi.internal.schema.ApiPageEntry.Type;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
Expand Down Expand Up @@ -196,7 +201,18 @@ public void handleCloseElement(final @Nullable String elementName, final int lin
sb = sb.delete(0, 0);
}
if (this.fieldType == FieldType.READ_ONLY || this.fieldType == FieldType.FORM_VALUE) {
int len = sb.length();
int lids = sb.lastIndexOf(":");
if (len - lids == 3) {
int lids2 = sb.lastIndexOf(":", lids - 1);
if (lids2 > 0 && (lids - lids2 >= 3 && lids - lids2 <= 7)) {
// the given value might be a time. validate it
String timeCandidate = sb.substring(lids2 + 1).trim();
if (timeCandidate.length() == 5 && timeCandidate.matches("[0-9]{2}:[0-9]{2}")) {
lids = lids2;
}
}
}
int fsp = sb.indexOf(" ");
if (fsp < 0 || lids < 0 || fsp > lids) {
logger.debug("Invalid format for setting {}:{}:{} [{}] : {}", id, line, col, this.fieldType,
Expand Down Expand Up @@ -401,16 +417,27 @@ private void getApiPageEntry(@Nullable String id2, int line, int col, String sho
type = Type.NUMERIC_FORM;
}
} catch (NumberFormatException nfe) {
// not a number...
channelType = "String";
ctuid = null;
// check for time....
String[] valParts = vs.split(":");
if (valParts.length == 2) {
channelType = "DateTime";
// convert it to zonedDateTime with today as date and the
// default timezone.
var zdt = LocalTime.parse(vs, DateTimeFormatter.ofPattern("HH:mm")).atDate(LocalDate.now())
.atZone(ZoneId.systemDefault());
state = new DateTimeType(zdt);
type = Type.NUMERIC_FORM;
} else {
// not a number and not time...
channelType = "String";
state = new StringType(vs);
type = Type.STATE_FORM;
}
if (this.fieldType == FieldType.READ_ONLY || this.address == null) {
ctuid = TACmiBindingConstants.CHANNEL_TYPE_SCHEME_STATE_RO_UID;
type = Type.READ_ONLY_STATE;
} else {
ctuid = null;
type = Type.STATE_FORM;
}
state = new StringType(vs);
}
}
break;
Expand Down Expand Up @@ -555,8 +582,11 @@ private ChannelType buildAndRegisterChannelType(String shortName, Type type, Cha
}
}
break;
case TIME:
itemType = "DateTime";
break;
default:
throw new IllegalStateException();
throw new IllegalStateException("Unhandled OptionType: " + cx2e.optionType);
}
ChannelTypeBuilder<?> ctb = ChannelTypeBuilder
.state(new ChannelTypeUID(TACmiBindingConstants.BINDING_ID, shortName), shortName, itemType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class ChangerX2Entry {
enum OptionType {
NUMBER,
SELECT,
TIME,
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void handleOpenElement(final String elementName, final Map<String, String
String type = attributes.get("type");
if ("number".equals(type)) {
this.optionType = OptionType.NUMBER;
// we transfer the limits from the input elemnt...
// we transfer the limits from the input element...
this.options.put(ChangerX2Entry.NUMBER_MIN, attributes.get(ChangerX2Entry.NUMBER_MIN));
this.options.put(ChangerX2Entry.NUMBER_MAX, attributes.get(ChangerX2Entry.NUMBER_MAX));
this.options.put(ChangerX2Entry.NUMBER_STEP, attributes.get(ChangerX2Entry.NUMBER_STEP));
Expand All @@ -120,6 +120,45 @@ public void handleOpenElement(final String elementName, final Map<String, String
col, attributes);
}
}
} else if ((this.parserState == ParserState.INIT || this.parserState == ParserState.INPUT)
&& "input".equals(elementName) && "changetotimeh".equals(id)) {
this.parserState = ParserState.INPUT_DATA;
if (attributes != null) {
this.optionFieldName = attributes.get("name");
String type = attributes.get("type");
if ("number".equals(attributes.get("type"))) {
this.optionType = OptionType.TIME;
// validate hour limits
if (!"0".equals(attributes.get(ChangerX2Entry.NUMBER_MIN))
|| !"24".equals(attributes.get(ChangerX2Entry.NUMBER_MAX))) {
logger.warn(
"Error parsing options for {}: Unexpected MIN/MAX values for hour input field in {}:{}: {}",
channelName, line, col, attributes);
}
;
} else {
logger.warn("Error parsing options for {}: Unhandled input field in {}:{}: {}", channelName, line,
col, attributes);
}
}
} else if ((this.parserState == ParserState.INPUT_DATA || this.parserState == ParserState.INPUT)
&& "input".equals(elementName) && "changetotimem".equals(id)) {
this.parserState = ParserState.INPUT_DATA;
if (attributes != null) {
if ("number".equals(attributes.get("type"))) {
this.optionType = OptionType.TIME;
if (!"0".equals(attributes.get(ChangerX2Entry.NUMBER_MIN))
|| !"59".equals(attributes.get(ChangerX2Entry.NUMBER_MAX))) {
logger.warn(
"Error parsing options for {}: Unexpected MIN/MAX values for minute input field in {}:{}: {}",
channelName, line, col, attributes);
}
;
} else {
logger.warn("Error parsing options for {}: Unhandled input field in {}:{}: {}", channelName, line,
col, attributes);
}
}
} else if (this.parserState == ParserState.SELECT && "option".equals(elementName)) {
this.parserState = ParserState.SELECT_OPTION;
this.optionType = OptionType.SELECT;
Expand All @@ -136,6 +175,8 @@ public void handleCloseElement(final @Nullable String elementName, final int lin
throws ParseException {
if (this.parserState == ParserState.INPUT && "input".equals(elementName)) {
this.parserState = ParserState.INIT;
} else if (this.parserState == ParserState.INPUT_DATA && "input".equals(elementName)) {
this.parserState = ParserState.INPUT;
} else if (this.parserState == ParserState.SELECT && "select".equals(elementName)) {
this.parserState = ParserState.INIT;
} else if (this.parserState == ParserState.SELECT_OPTION && "option".equals(elementName)) {
Expand All @@ -159,6 +200,8 @@ public void handleCloseElement(final @Nullable String elementName, final int lin
channelName, line, col, value, prev, id);
}
}
} else if (this.parserState == ParserState.INPUT && "span".equals(elementName)) {
// span's are ignored...
} else {
logger.debug("Error parsing options for {}: Unexpected CloseElement in {}:{}: {}", channelName, line, col,
elementName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.binding.tacmi.internal.TACmiChannelTypeProvider;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Channel;
Expand Down Expand Up @@ -257,6 +258,10 @@ public void handleCommand(final ChannelUID channelUID, final Command command) {
String val;
if (command instanceof Number qt) {
val = String.format(Locale.US, "%.2f", qt.floatValue());
} else if (command instanceof DateTimeType dtt) {
// time is transferred as minutes since midnight...
var zdt = dtt.getZonedDateTime();
val = Integer.toString(zdt.getHour() * 60 + zdt.getMinute());
} else {
val = command.format("%.2f");
}
Expand Down

0 comments on commit 1f6c2c6

Please sign in to comment.