diff --git a/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/channel-types.adoc b/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/channel-types.adoc index 4fb41e2b..52cd39d7 100644 --- a/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/channel-types.adoc +++ b/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/channel-types.adoc @@ -5,9 +5,15 @@ |=== |Channel type | Label ^|Description +| co7io-fatek:contact +| Contact +| A read only channel which represent state of input or output. + +<> + | co7io-fatek:discrete -| Discrete register -| Discrete register of connected PLC. +| Switchable discrete register +| Discrete register of connected PLC which can be commanded. <> @@ -23,6 +29,18 @@ <> +| co7io-fatek:percent16 +| Percent (16-bit) +| Data register for representing percentage expressed as integer (0 ... 100) based on 16 bit register. + +<> + +| co7io-fatek:percent32 +| Percent (32-bit) +| Data register for representing percentage in range as integer or floating point number based on 32 bit register. + +<> + | co7io-fatek:rollershutter16 | Rollershutter (16-bit) | Data register for position will use 16 bit registers. @@ -50,6 +68,38 @@ |=== +[[co7io-fatek:contact]] +== Configuration of `co7io-fatek:contact` + +Below table contain configuration parameters which can be assigned to channels of type `co7io-fatek:contact`. + +[width="100%",caption="Channel type contact configuration",cols="1,1,1,2"] +|=== +|Name | Type | Label ^|Description + +| register +| TEXT +| Register +| Type of discrete register to read or write. + +| index +| INTEGER +| Register index +| Index of register used to retrieve data. + +| invert +| BOOLEAN +| Invert +| Invert logical representation of related register (0->1, 1->0). + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + +|=== + + [[co7io-fatek:discrete]] == Configuration of `co7io-fatek:discrete` @@ -74,6 +124,11 @@ Below table contain configuration parameters which can be assigned to channels o | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== @@ -101,6 +156,11 @@ Below table contain configuration parameters which can be assigned to channels o | Unsigned | Values retrieved from and written to device assume unsigned representation. +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== @@ -123,19 +183,62 @@ Below table contain configuration parameters which can be assigned to channels o | Register index | Index of register used to retrieve data. -| unsigned -| BOOLEAN -| Unsigned -| Values retrieved from and written to device assume unsigned representation. Does not apply if floating option is set. - | floating | BOOLEAN | floating point | Indicate that read/write value is a floating point number. Overrides unsigned flag. +| step +| DECIMAL +| Step +| Value assumed for increase/decrease command. + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== +[[co7io-fatek:percent16]] +== Configuration of `co7io-fatek:percent16` + +Below table contain configuration parameters which can be assigned to channels of type `co7io-fatek:percent16`. + +[width="100%",caption="Channel type percent16 configuration",cols="1,1,1,2"] +|=== +|Name | Type | Label ^|Description + +| register +| TEXT +| Register +| Type of data register to read or write. + +| index +| INTEGER +| Register index +| Index of register used to retrieve data. + +| step +| INTEGER +| Step +| Value assumed for increase/decrease command. + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + +|=== + + +[[co7io-fatek:percent32]] +== Configuration of `co7io-fatek:percent32` + +Below table contain configuration parameters which can be assigned to channels of type `co7io-fatek:percent32`. + + [[co7io-fatek:rollershutter16]] == Configuration of `co7io-fatek:rollershutter16` @@ -195,6 +298,11 @@ Below table contain configuration parameters which can be assigned to channels o | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== @@ -257,6 +365,11 @@ Below table contain configuration parameters which can be assigned to channels o | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== @@ -299,11 +412,21 @@ Below table contain configuration parameters which can be assigned to channels o | Register index | Index of register used to retrieve data. +| step +| DECIMAL +| Step +| Value assumed for increase/decrease command. + | rgb | BOOLEAN | RGB mode | Write and interpret read data as RGB code instead of HSB. +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + | switcherRegister | TEXT | Register diff --git a/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/config-descriptions.adoc b/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/config-descriptions.adoc index 39c7f706..ed90759f 100644 --- a/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/config-descriptions.adoc +++ b/bundles/org.connectorio.addons.binding.fatek/docs/fatek/descriptors/config-descriptions.adoc @@ -18,16 +18,21 @@ | Register index | Index of register used to retrieve data. -| unsigned -| BOOLEAN -| Unsigned -| Values retrieved from and written to device assume unsigned representation. Does not apply if floating option is set. - | floating | BOOLEAN | floating point | Indicate that read/write value is a floating point number. Overrides unsigned flag. +| step +| DECIMAL +| Step +| Value assumed for increase/decrease command. + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== [[thing-type:co7io-fatek:tcp]] @@ -114,6 +119,34 @@ |=== +[[channel-type:co7io-fatek:contact]] +== Config `channel-type:co7io-fatek:contact` +[width="100%",caption="channel-type:co7io-fatek:contact configuration",cols="1,1,1,2"] +|=== +|Name | Type | Label ^|Description + +| register +| TEXT +| Register +| Type of discrete register to read or write. + +| index +| INTEGER +| Register index +| Index of register used to retrieve data. + +| invert +| BOOLEAN +| Invert +| Invert logical representation of related register (0->1, 1->0). + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + +|=== + [[channel-type:co7io-fatek:binary]] == Config `channel-type:co7io-fatek:binary` [width="100%",caption="channel-type:co7io-fatek:binary configuration",cols="1,1,1,2"] @@ -135,6 +168,39 @@ | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + +|=== + +[[channel-type:co7io-fatek:percent16]] +== Config `channel-type:co7io-fatek:percent16` +[width="100%",caption="channel-type:co7io-fatek:percent16 configuration",cols="1,1,1,2"] +|=== +|Name | Type | Label ^|Description + +| register +| TEXT +| Register +| Type of data register to read or write. + +| index +| INTEGER +| Register index +| Index of register used to retrieve data. + +| step +| INTEGER +| Step +| Value assumed for increase/decrease command. + +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== [[channel-type:co7io-fatek:rollershutter32]] @@ -193,6 +259,11 @@ | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== [[channel-type:co7io-fatek:data16]] @@ -216,6 +287,11 @@ | Unsigned | Values retrieved from and written to device assume unsigned representation. +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== [[channel-type:co7io-fatek:rollershutter16]] @@ -274,6 +350,11 @@ | Invert | Invert logical representation of related register (0->1, 1->0). +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + |=== [[channel-type:co7io-fatek:color16]] @@ -312,11 +393,21 @@ | Register index | Index of register used to retrieve data. +| step +| DECIMAL +| Step +| Value assumed for increase/decrease command. + | rgb | BOOLEAN | RGB mode | Write and interpret read data as RGB code instead of HSB. +| refreshInterval +| INTEGER +| Refresh interval +| Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + | switcherRegister | TEXT | Register diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/FatekBindingConstants.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/FatekBindingConstants.java index ad8b043e..36220872 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/FatekBindingConstants.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/FatekBindingConstants.java @@ -40,9 +40,12 @@ public interface FatekBindingConstants extends BaseBindingConstants { )); // common dynamic channel types + ChannelTypeUID CHANNEL_TYPE_CONTACT = new ChannelTypeUID(BINDING_ID, "contact"); ChannelTypeUID CHANNEL_TYPE_DISCRETE = new ChannelTypeUID(BINDING_ID, "discrete"); ChannelTypeUID CHANNEL_TYPE_DATA16 = new ChannelTypeUID(BINDING_ID, "data16"); ChannelTypeUID CHANNEL_TYPE_DATA32 = new ChannelTypeUID(BINDING_ID, "data32"); + ChannelTypeUID CHANNEL_TYPE_PERCENT16 = new ChannelTypeUID(BINDING_ID, "percent16"); + ChannelTypeUID CHANNEL_TYPE_PERCENT32 = new ChannelTypeUID(BINDING_ID, "percent32"); ChannelTypeUID CHANNEL_TYPE_ROLLERSHUTTER16 = new ChannelTypeUID(BINDING_ID, "rollershutter16"); ChannelTypeUID CHANNEL_TYPE_ROLLERSHUTTER32 = new ChannelTypeUID(BINDING_ID, "rollershutter32"); ChannelTypeUID CHANNEL_TYPE_COLOR16 = new ChannelTypeUID(BINDING_ID, "color16"); diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/BaseChannelConfig.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/BaseChannelConfig.java index 83f7eb22..2015346f 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/BaseChannelConfig.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/BaseChannelConfig.java @@ -17,9 +17,10 @@ */ package org.connectorio.addons.binding.fatek.config.channel; +import org.connectorio.addons.binding.config.PollingConfiguration; import org.simplify4u.jfatek.registers.RegName; -public abstract class BaseChannelConfig implements RegisterConfig { +public abstract class BaseChannelConfig extends PollingConfiguration implements RegisterConfig { public int index; diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/Percent32ChannelConfig.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/Percent32ChannelConfig.java new file mode 100644 index 00000000..c8c61fcc --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/Percent32ChannelConfig.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.config.channel.percent; + +public class Percent32ChannelConfig extends PercentChannelConfig { + + public boolean floating; + +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/PercentChannelConfig.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/PercentChannelConfig.java new file mode 100644 index 00000000..8d3d25f3 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/config/channel/percent/PercentChannelConfig.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.config.channel.percent; + +import java.math.BigDecimal; +import org.connectorio.addons.binding.fatek.config.channel.BaseChannelConfig; +import org.simplify4u.jfatek.registers.RegName; + +public class PercentChannelConfig extends BaseChannelConfig { + + public boolean unsigned; + public BigDecimal step = BigDecimal.valueOf(5); + + public PercentChannelConfig() {} + + public PercentChannelConfig(RegName register, int index) { + this.register = register; + this.index = index; + } + +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/BinaryChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/BinaryChannelHandler.java index 782f894e..7058048a 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/BinaryChannelHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/BinaryChannelHandler.java @@ -66,4 +66,9 @@ public State state(List value) { return converter.toState(value.get(0)); } + @Override + public String validateConfiguration() { + return null; + } + } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/ColorChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/ColorChannelHandler.java index b5ca4645..91233158 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/ColorChannelHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/ColorChannelHandler.java @@ -133,5 +133,12 @@ public State state(List value) { return convertedState; } + @Override + public String validateConfiguration() { + if (color1.equals(color2) || color1.equals(color3) || color2.equals(color3)) { + return "Color registers must be distinct!"; + } + return null; + } } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DataChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DataChannelHandler.java index 2a9d51e7..a5b8309f 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DataChannelHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DataChannelHandler.java @@ -68,4 +68,9 @@ public State state(List value) { return converter.toState(value.get(0)); } + @Override + public String validateConfiguration() { + return null; + } + } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DefaultChannelHandlerFactory.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DefaultChannelHandlerFactory.java index a19e83a5..19c0448d 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DefaultChannelHandlerFactory.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/DefaultChannelHandlerFactory.java @@ -22,14 +22,19 @@ import org.connectorio.addons.binding.fatek.config.channel.color.ColorChannelConfig; import org.connectorio.addons.binding.fatek.config.channel.data.Data32ChannelConfig; import org.connectorio.addons.binding.fatek.config.channel.data.DataChannelConfig; +import org.connectorio.addons.binding.fatek.config.channel.percent.Percent32ChannelConfig; +import org.connectorio.addons.binding.fatek.config.channel.percent.PercentChannelConfig; import org.connectorio.addons.binding.fatek.config.channel.rollershutter.RollerShutter32ChannelConfig; import org.connectorio.addons.binding.fatek.config.channel.rollershutter.RollerShutterChannelConfig; import org.connectorio.addons.binding.fatek.internal.RegisterParser; import org.connectorio.addons.binding.fatek.internal.channel.converter.ColorConverter; +import org.connectorio.addons.binding.fatek.internal.channel.converter.ContactConverter; import org.connectorio.addons.binding.fatek.internal.channel.converter.Converter; import org.connectorio.addons.binding.fatek.internal.channel.converter.Data16Converter; import org.connectorio.addons.binding.fatek.internal.channel.converter.Data32Converter; import org.connectorio.addons.binding.fatek.internal.channel.converter.DiscreteConverter; +import org.connectorio.addons.binding.fatek.internal.channel.converter.Percent16Converter; +import org.connectorio.addons.binding.fatek.internal.channel.converter.Percent32Converter; import org.openhab.core.thing.Channel; import org.simplify4u.jfatek.registers.DataReg; import org.simplify4u.jfatek.registers.DisReg; @@ -38,7 +43,10 @@ public class DefaultChannelHandlerFactory implements FatekChannelHandlerFactory @Override public FatekChannelHandler create(Channel channel) { - if (FatekBindingConstants.CHANNEL_TYPE_DISCRETE.equals(channel.getChannelTypeUID())) { + if (FatekBindingConstants.CHANNEL_TYPE_CONTACT.equals(channel.getChannelTypeUID())) { + DiscreteChannelConfig config = channel.getConfiguration().as(DiscreteChannelConfig.class); + return new BinaryChannelHandler(channel, RegisterParser.parseDiscrete(config), new ContactConverter(config)); + } else if (FatekBindingConstants.CHANNEL_TYPE_DISCRETE.equals(channel.getChannelTypeUID())) { DiscreteChannelConfig config = channel.getConfiguration().as(DiscreteChannelConfig.class); return new BinaryChannelHandler(channel, RegisterParser.parseDiscrete(config), new DiscreteConverter(config)); } @@ -50,6 +58,18 @@ public FatekChannelHandler create(Channel channel) { Data32ChannelConfig config = channel.getConfiguration().as(Data32ChannelConfig.class); return new DataChannelHandler(channel, RegisterParser.parseData32(config), new Data32Converter(config)); } + if (FatekBindingConstants.CHANNEL_TYPE_PERCENT16.equals(channel.getChannelTypeUID())) { + PercentChannelConfig config = channel.getConfiguration().as(PercentChannelConfig.class); + return new PercentChannelHandler(channel, config.step, RegisterParser.parseData16(config), + new Percent16Converter(config) + ); + } + if (FatekBindingConstants.CHANNEL_TYPE_PERCENT32.equals(channel.getChannelTypeUID())) { + Percent32ChannelConfig config = channel.getConfiguration().as(Percent32ChannelConfig.class); + return new PercentChannelHandler(channel, config.step, RegisterParser.parseData16(config), + new Percent32Converter(config) + ); + } if (FatekBindingConstants.CHANNEL_TYPE_ROLLERSHUTTER16.equals(channel.getChannelTypeUID())) { RollerShutterChannelConfig config = channel.getConfiguration().as(RollerShutterChannelConfig.class); DiscreteChannelConfig startCfg = new DiscreteChannelConfig(config.startRegister, config.startIndex, config.startInvert); diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/FatekChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/FatekChannelHandler.java index 24e85de6..54158512 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/FatekChannelHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/FatekChannelHandler.java @@ -36,4 +36,5 @@ public interface FatekChannelHandler { // fetch State state(List value); + String validateConfiguration(); } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/PercentChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/PercentChannelHandler.java new file mode 100644 index 00000000..4d6c6f0c --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/PercentChannelHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.channel; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import org.connectorio.addons.binding.fatek.internal.channel.converter.Converter; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.IncreaseDecreaseType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.simplify4u.jfatek.FatekCommand; +import org.simplify4u.jfatek.FatekWriteDataCmd; +import org.simplify4u.jfatek.registers.DataReg; +import org.simplify4u.jfatek.registers.Reg; +import org.simplify4u.jfatek.registers.RegValue; +import org.simplify4u.jfatek.registers.RegValueData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PercentChannelHandler implements FatekChannelHandler { + + private final Logger logger = LoggerFactory.getLogger(PercentChannelHandler.class); + + private final ChannelUID channel; + private final BigDecimal step; + private final DataReg register; + private final Converter converter; + + private final AtomicReference state = new AtomicReference<>(); + + public PercentChannelHandler(Channel channel, BigDecimal step, DataReg register, Converter converter) { + this.channel = channel.getUID(); + this.step = step; + this.register = register; + this.converter = converter; + } + + @Override + public List registers() { + return Collections.singletonList(register); + } + + @Override + public ChannelUID channel() { + return channel; + } + + @Override + public FatekCommand prepareWrite(Command command) { + RegValue value = converter.toValue(command); + if (value instanceof RegValueData) { + return new FatekWriteDataCmd(null, register, (RegValueData) value); + } + + if (command instanceof IncreaseDecreaseType) { + if (state.get() == null) { + logger.warn("Could not handle command {} for channel {}. State of channel is not yet known", command, channel); + return null; + } + + BigDecimal decimal = state.get().toBigDecimal(); + if (IncreaseDecreaseType.INCREASE.equals(command)) { + decimal = decimal.add(step).min(Percentage.HUNDRED); + return write(Percentage.from(decimal)); + } + if (IncreaseDecreaseType.DECREASE.equals(command)) { + decimal = decimal.subtract(step).max(Percentage.ZERO); + return write(Percentage.from(decimal)); + } + + } + return null; + } + + private FatekWriteDataCmd write(PercentType percentage) { + RegValue value = converter.toValue(percentage); + if (value instanceof RegValueData) { + return new FatekWriteDataCmd(null, register, (RegValueData) value); + } + return null; + } + + @Override + public State state(List value) { + State convertedState = converter.toState(value.get(0)); + if (convertedState instanceof DecimalType) { + state.set((DecimalType) convertedState); + } + return convertedState; + } + + @Override + public String validateConfiguration() { + return null; + } + +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/Percentage.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/Percentage.java new file mode 100644 index 00000000..b40814a2 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/Percentage.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.channel; + +import java.math.BigDecimal; +import org.openhab.core.library.types.PercentType; + +public interface Percentage { + + BigDecimal ZERO = BigDecimal.ZERO; + + BigDecimal HUNDRED = BigDecimal.valueOf(100); + + static PercentType from(BigDecimal decimal) { + return new PercentType(decimal.min(HUNDRED).max(ZERO)); + } + +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/RollerShutterChannelHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/RollerShutterChannelHandler.java index b0ea4573..d89fb4c6 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/RollerShutterChannelHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/RollerShutterChannelHandler.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import org.connectorio.addons.binding.fatek.internal.channel.converter.Converter; +import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StopMoveType; import org.openhab.core.library.types.UpDownType; @@ -112,4 +113,12 @@ public State state(List value) { return positionConverter.toState(value.get(0)); } + @Override + public String validateConfiguration() { + if (startReg == stopReg) { + return "Start and stop registers must differ!"; + } + return null; + } + } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/ContactConverter.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/ContactConverter.java new file mode 100644 index 00000000..38dc24e1 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/ContactConverter.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.channel.converter; + +import org.connectorio.addons.binding.fatek.config.channel.binary.DiscreteChannelConfig; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.OpenClosedType; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.simplify4u.jfatek.registers.RegValue; +import org.simplify4u.jfatek.registers.RegValueDis; + +public class ContactConverter implements Converter { + + private final DiscreteChannelConfig config; + + public ContactConverter(DiscreteChannelConfig config) { + this.config = config; + } + + @Override + public RegValue toValue(Command command) { + return null; + } + + @Override + public State toState(RegValue value) { + boolean status = config.invert ? !value.boolValue() : value.boolValue(); + return status ? OpenClosedType.CLOSED : OpenClosedType.OPEN; + } +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/DiscreteConverter.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/DiscreteConverter.java index 832611e5..239009bb 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/DiscreteConverter.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/DiscreteConverter.java @@ -35,13 +35,7 @@ public DiscreteConverter(DiscreteChannelConfig config) { @Override public RegValue toValue(Command command) { - boolean value; - if (command instanceof OpenClosedType) { - value = OpenClosedType.CLOSED == command; - } else { - value = OnOffType.ON == command; - } - + boolean value = OnOffType.ON == command; if (value) { return config.invert ? RegValueDis.FALSE : RegValueDis.TRUE; } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent16Converter.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent16Converter.java new file mode 100644 index 00000000..1b8d7c0f --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent16Converter.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.channel.converter; + +import java.math.BigInteger; +import org.connectorio.addons.binding.fatek.config.channel.data.DataChannelConfig; +import org.connectorio.addons.binding.fatek.config.channel.percent.PercentChannelConfig; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.simplify4u.jfatek.registers.RegValue; +import org.simplify4u.jfatek.registers.RegValue32; + +public class Percent16Converter implements Converter { + + private final PercentChannelConfig config; + + public Percent16Converter(PercentChannelConfig config) { + this.config = config; + } + + @Override + public RegValue toValue(Command command) { + if (!(command instanceof PercentType)) { + return null; + } + + PercentType percentType = (PercentType) command; + long longValue = percentType.toBigDecimal().longValue(); + return new RegValue32(config.unsigned ? BigInteger.valueOf(longValue).longValue() : longValue); + } + + @Override + public State toState(RegValue value) { + int number = config.unsigned ? value.intValueUnsigned() : value.intValue(); + number = Math.min(number, 100); + number = Math.max(number, 0); + return new PercentType(number); + } +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent32Converter.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent32Converter.java new file mode 100644 index 00000000..04a587f2 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/channel/converter/Percent32Converter.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.channel.converter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import org.connectorio.addons.binding.fatek.config.channel.percent.Percent32ChannelConfig; +import org.connectorio.addons.binding.fatek.internal.channel.Percentage; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.simplify4u.jfatek.registers.RegValue; +import org.simplify4u.jfatek.registers.RegValue32; + +public class Percent32Converter implements Converter { + + private final Percent32ChannelConfig config; + + public Percent32Converter(Percent32ChannelConfig config) { + this.config = config; + } + + @Override + public RegValue toValue(Command command) { + if (!(command instanceof PercentType)) { + return null; + } + + PercentType percentType = (PercentType) command; + if (config.floating) { + return new RegValue32(Float.floatToIntBits(percentType.toBigDecimal().floatValue())); + } + + long longValue = percentType.toBigDecimal().longValue(); + return new RegValue32(config.unsigned ? BigInteger.valueOf(longValue).longValue() : longValue); + } + + @Override + public State toState(RegValue value) { + if (config.floating) { + BigDecimal decimal = BigDecimal.valueOf(value.floatValue()); + return new PercentType(decimal.max(Percentage.HUNDRED).min(Percentage.ZERO)); + } + + int number = config.unsigned ? value.intValueUnsigned() : value.intValue(); + number = Math.min(number, 100); + number = Math.max(number, 0); + return new PercentType(number); + } +} diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekPlcThingHandler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekPlcThingHandler.java index bd05d8dd..12d42467 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekPlcThingHandler.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekPlcThingHandler.java @@ -17,51 +17,52 @@ */ package org.connectorio.addons.binding.fatek.internal.handler; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import org.connectorio.addons.binding.config.PollingConfiguration; import org.connectorio.addons.binding.fatek.config.BridgeConfig; import org.connectorio.addons.binding.fatek.config.DeviceConfig; import org.connectorio.addons.binding.fatek.internal.channel.FatekChannelHandler; import org.connectorio.addons.binding.fatek.internal.channel.FatekChannelHandlerFactory; +import org.connectorio.addons.binding.fatek.internal.handler.source.FatekSamplerComposer; +import org.connectorio.addons.binding.fatek.internal.handler.source.FatekRegisterSampler; +import org.connectorio.addons.binding.fatek.internal.handler.source.FatekSampler; import org.connectorio.addons.binding.fatek.transport.FaconConnection; -import org.connectorio.addons.binding.handler.PollingHandler; import org.connectorio.addons.binding.handler.polling.common.BasePollingThingHandler; +import org.connectorio.addons.binding.source.SourceFactory; +import org.connectorio.addons.binding.source.sampling.SamplingSource; import org.openhab.core.thing.Channel; 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.types.Command; +import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; import org.openhab.core.types.Type; import org.simplify4u.jfatek.FatekCommand; -import org.simplify4u.jfatek.FatekReadMixDataCmd; import org.simplify4u.jfatek.registers.Reg; import org.simplify4u.jfatek.registers.RegValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class FatekPlcThingHandler extends BasePollingThingHandler, DeviceConfig> - implements Runnable { +public class FatekPlcThingHandler extends BasePollingThingHandler, DeviceConfig> { private final Logger logger = LoggerFactory.getLogger(FatekPlcThingHandler.class); + private final SourceFactory sourceFactory; private final FatekChannelHandlerFactory channelHandlerFactory; private final Map handlerMap = new ConcurrentHashMap<>(); - private final Map registerMap = new ConcurrentHashMap<>(); private FaconConnection connection; private Integer stationNumber; - private ScheduledFuture future; + private SamplingSource source; - public FatekPlcThingHandler(Thing thing, FatekChannelHandlerFactory channelHandlerFactory) { + public FatekPlcThingHandler(Thing thing, SourceFactory sourceFactory, FatekChannelHandlerFactory channelHandlerFactory) { super(thing); + this.sourceFactory = sourceFactory; this.channelHandlerFactory = channelHandlerFactory; } @@ -89,19 +90,28 @@ public void initialize() { } this.connection = result; + this.source = sourceFactory.sampling(scheduler, new FatekSamplerComposer(connection, stationNumber)); + StringBuilder validation = new StringBuilder(); for (Channel channel : getThing().getChannels()) { FatekChannelHandler handler = channelHandlerFactory.create(channel); - if (handler != null) { - handlerMap.put(channel.getUID(), handler); - for (Reg register : handler.registers()) { - registerMap.put(register, handler); + if (handler != null) {String validationMsg = handler.validateConfiguration(); + if (validationMsg != null && !validationMsg.isEmpty()) { + validation.append(validationMsg); } + Long refreshInterval = Optional.ofNullable(channel.getConfiguration().as(PollingConfiguration.class)) + .map(cfg -> cfg.refreshInterval) + .filter(interval -> interval != 0) + .orElseGet(this::getRefreshInterval); + source.add(refreshInterval, channel.getUID().getAsString(), new FatekRegisterSampler(connection, stationNumber, handler.registers(), new HandlerCallback(handler, this::update))); + handlerMap.put(channel.getUID(), handler); } } - Long interval = getThingConfig().map(cfg -> cfg.refreshInterval) - .orElseGet(() -> getBridgeHandler().map(PollingHandler::getRefreshInterval) - .orElseGet(this::getDefaultPollingInterval)); - future = scheduler.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS); + + if (validation.length() != 0) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, validation.toString()); + return; + } + source.start(); updateStatus(ThingStatus.ONLINE); }); @@ -111,6 +121,11 @@ public void initialize() { public void handleCommand(ChannelUID channelUID, Command command) { if (handlerMap.containsKey(channelUID)) { FatekChannelHandler handler = handlerMap.get(channelUID); + if (RefreshType.REFRESH.equals(command) && this.source != null) { + // read channel status independently of scheduled tasks + source.request(new FatekRegisterSampler(connection, stationNumber, handler.registers(), new HandlerCallback(handler, this::update))); + return; + } FatekCommand cmd = handler.prepareWrite(command); if (cmd == null) { logger.warn("Could not map command {} from channel {} to value supported by PLC. Ignoring this write.", command, channelUID); @@ -128,7 +143,6 @@ private void write(ChannelUID channel, Command command, FatekCommand cmd) { return; } logger.debug("Successful write of channel {} with command {} annd fatek command {}", channel, command, cmd); - update(channel, command); }); } @@ -140,8 +154,8 @@ private void update(ChannelUID channelUID, Type value) { @Override public void dispose() { - if (future != null) { - future.cancel(false); + if (source != null) { + source.stop(); } super.dispose(); } @@ -151,33 +165,21 @@ protected Long getDefaultPollingInterval() { return 1000L; } - @Override - public void run() { - connection.execute(stationNumber, new FatekReadMixDataCmd(null, registerMap.keySet())).whenComplete((result, error) -> { - if (error != null) { - logger.warn("Failed to retrieve data", error); - return; - } - callChannelHandlers(result); - }); - } + static class HandlerCallback implements Consumer> { - private void callChannelHandlers(Map result) { - Set called = new HashSet<>(); - for (Entry entry : result.entrySet()) { - FatekChannelHandler handler = registerMap.get(entry.getKey()); - if (!called.contains(handler)) { - // handler have not been called yet, lets collect its registers and let it parse data - List values = new ArrayList<>(); - for (Reg register : handler.registers()) { - values.add(result.get(register)); - } - // convert values to OH state - State state = handler.state(values); - if (state != null) { - update(handler.channel(), state); - } - called.add(handler); + private final FatekChannelHandler handler; + private final BiConsumer callback; + + public HandlerCallback(FatekChannelHandler handler, BiConsumer callback) { + this.handler = handler; + this.callback = callback; + } + + @Override + public void accept(Map regValues) { + State state = handler.state(new ArrayList<>(regValues.values())); + if (state != null) { + callback.accept(handler.channel(), state); } } } diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekThingHandlerFactory.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekThingHandlerFactory.java index 9313a4aa..3adf6281 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekThingHandlerFactory.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/FatekThingHandlerFactory.java @@ -22,6 +22,7 @@ import org.connectorio.addons.binding.fatek.internal.channel.FatekChannelHandlerFactory; import org.connectorio.addons.binding.handler.factory.BaseThingHandlerFactory; import org.connectorio.addons.binding.fatek.internal.discovery.DiscoveryCoordinator; +import org.connectorio.addons.binding.source.SourceFactory; import org.openhab.core.io.transport.serial.SerialPortManager; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; @@ -38,13 +39,16 @@ public class FatekThingHandlerFactory extends BaseThingHandlerFactory { private final FatekChannelHandlerFactory channelHandlerFactory = new DefaultChannelHandlerFactory(); private final FatekConnectionFactory serialConnectionFactory; private final DiscoveryCoordinator discoveryCoordinator; + private final SourceFactory sourceFactory; // The connection factory argument is artificial, its here just to force proper initialization order @Activate - public FatekThingHandlerFactory(@Reference FatekConnectionFactory connectionFactory, @Reference DiscoveryCoordinator discoveryCoordinator) { + public FatekThingHandlerFactory(@Reference FatekConnectionFactory connectionFactory, @Reference DiscoveryCoordinator discoveryCoordinator, + @Reference(target = "(default=true)") SourceFactory sourceFactory) { super(FatekBindingConstants.SUPPORTED_THING_TYPES); this.serialConnectionFactory = connectionFactory; this.discoveryCoordinator = discoveryCoordinator; + this.sourceFactory = sourceFactory; } @Override @@ -59,7 +63,7 @@ protected ThingHandler createHandler(Thing thing) { } if (FatekBindingConstants.PLC_THING_TYPE.equals(thing.getThingTypeUID())) { - return new FatekPlcThingHandler(thing, channelHandlerFactory); + return new FatekPlcThingHandler(thing, sourceFactory, channelHandlerFactory); } return null; diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekRegisterSampler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekRegisterSampler.java new file mode 100644 index 00000000..00c5ceb0 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekRegisterSampler.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.handler.source; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import org.connectorio.addons.binding.fatek.transport.FaconConnection; +import org.simplify4u.jfatek.FatekReadMixDataCmd; +import org.simplify4u.jfatek.registers.Reg; +import org.simplify4u.jfatek.registers.RegValue; + +public class FatekRegisterSampler implements FatekSampler { + + private final FaconConnection connection; + private final int stationNumber; + private final List registers; + private final Consumer> consumer; + + public FatekRegisterSampler(FaconConnection connection, int stationNumber, List registers, Consumer> consumer) { + this.connection = connection; + this.stationNumber = stationNumber; + this.registers = registers; + this.consumer = consumer; + } + + @Override + public CompletableFuture> fetch() { + return connection.execute(stationNumber, new FatekReadMixDataCmd(null, registers.toArray(new Reg[0]))) + .whenComplete((result, error) -> { + if (error != null) { + return; + } + consumer.accept(result); + }); + } + + public List getRegisters() { + return registers; + } + + @Override + public Consumer> getCallback() { + return consumer; + } +} \ No newline at end of file diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSampler.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSampler.java new file mode 100644 index 00000000..31f35fbe --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSampler.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.handler.source; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.connectorio.addons.binding.source.sampling.Sampler; +import org.simplify4u.jfatek.registers.Reg; +import org.simplify4u.jfatek.registers.RegValue; + +/** + * Dedicated interface for sampler which interacts with Fatek PLCs. + */ +public interface FatekSampler extends Sampler { + + List getRegisters(); + Consumer> getCallback(); + +} \ No newline at end of file diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSamplerComposer.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSamplerComposer.java new file mode 100644 index 00000000..61a56855 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/handler/source/FatekSamplerComposer.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2024-2024 ConnectorIO Sp. z o.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.connectorio.addons.binding.fatek.internal.handler.source; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.connectorio.addons.binding.fatek.transport.FaconConnection; +import org.connectorio.addons.binding.source.sampling.SamplerComposer; +import org.simplify4u.jfatek.registers.Reg; +import org.simplify4u.jfatek.registers.RegValue; + +/** + * Composer which merges individual register scanners into one larger one which rely on read mix data + * command. + */ +public class FatekSamplerComposer implements SamplerComposer { + + private final FaconConnection connection; + private final int stationNumber; + + public FatekSamplerComposer(FaconConnection connection, int stationNumber) { + this.connection = connection; + this.stationNumber = stationNumber; + } + + @Override + public List merge(List samplers) { + if (samplers.size() == 1) { + return samplers; + } + + List registers = new ArrayList<>(); + List callbacks = new ArrayList<>(); + + for (FatekSampler sampler : samplers) { + List samplerRegisters = sampler.getRegisters(); + registers.addAll(samplerRegisters); + callbacks.add(new WrappedCallback(samplerRegisters, sampler.getCallback())); + } + + return Collections.singletonList(new FatekRegisterSampler( + connection, stationNumber, registers, new CompositeCallback(callbacks) + )); + } + + static class CompositeCallback implements Consumer> { + + private final List consumers; + + public CompositeCallback(List consumers) { + this.consumers = consumers; + } + + public void accept(Map result) { + int index = 0; + while (index < result.size()) { + // get subset of registers needed by given sampler + WrappedCallback callback = consumers.get(index++); + Map values = new LinkedHashMap<>(); + for (Reg register : callback.registers) { + values.put(register, result.get(register)); + } + callback.accept(values); + } + } + } + + static class WrappedCallback implements Consumer> { + + private final List registers; + private final Consumer> callback; + + public WrappedCallback(List registers, Consumer> callback) { + this.registers = registers; + this.callback = callback; + } + + @Override + public void accept(Map result) { + this.callback.accept(result); + } + } + +} \ No newline at end of file diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/transport/JFatekFaconConnection.java b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/transport/JFatekFaconConnection.java index 334ef5fa..7f81037c 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/transport/JFatekFaconConnection.java +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/java/org/connectorio/addons/binding/fatek/internal/transport/JFatekFaconConnection.java @@ -22,7 +22,6 @@ import java.util.concurrent.ExecutorService; import org.connectorio.addons.binding.fatek.internal.transport.command.MultiplexCmd; import org.connectorio.addons.binding.fatek.transport.FaconConnection; -import org.openhab.core.config.core.status.ConfigStatusMessage.Builder; import org.simplify4u.jfatek.FatekCommand; import org.simplify4u.jfatek.FatekException; import org.simplify4u.jfatek.FatekPLC; diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/binary-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/binary-channel-config.xml index 74e12a87..31246803 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/binary-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/binary-channel-config.xml @@ -27,7 +27,6 @@ Type of discrete register to read or write. - @@ -44,6 +43,11 @@ Invert logical representation of related register (0->1, 1->0). false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color16-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color16-channel-config.xml index 0b6c0be6..888e543f 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color16-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color16-channel-config.xml @@ -108,11 +108,21 @@ 0 - + + + Value assumed for increase/decrease command. + 5 + + Write and interpret read data as RGB code instead of HSB. false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color32-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color32-channel-config.xml index cccb4e3a..fc4a0908 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color32-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/color32-channel-config.xml @@ -108,11 +108,21 @@ 0 - + + + Value assumed for increase/decrease command. + 5 + + Write and interpret read data as RGB code instead of HSB. false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/contact-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/contact-channel-config.xml new file mode 100644 index 00000000..6de5c92d --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/contact-channel-config.xml @@ -0,0 +1,54 @@ + + + + + + + + Type of discrete register to read or write. + + + + + + + + + + + + Index of register used to retrieve data. + 0 + + + + Invert logical representation of related register (0->1, 1->0). + false + + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + + + + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data16-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data16-channel-config.xml index 7f36fa59..c2d21ab0 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data16-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data16-channel-config.xml @@ -52,6 +52,11 @@ Values retrieved from and written to device assume unsigned representation. false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data32-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data32-channel-config.xml index a4ba1c0e..0548d00f 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data32-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/data32-channel-config.xml @@ -57,6 +57,11 @@ Indicate that read/write value is a floating point number. Overrides unsigned flag. false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent16-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent16-channel-config.xml new file mode 100644 index 00000000..e63b7878 --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent16-channel-config.xml @@ -0,0 +1,62 @@ + + + + + + + + Type of data register to read or write. + + + + + + + + + + + + + + + + + + + + Index of register used to retrieve data. + 0 + + + + Value assumed for increase/decrease command. + 5 + + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + + + + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent32-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent32-channel-config.xml new file mode 100644 index 00000000..512d0bfa --- /dev/null +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/percent32-channel-config.xml @@ -0,0 +1,67 @@ + + + + + + + + Type of data register to read or write. + + + + + + + + + + + + + + + + + + + + Index of register used to retrieve data. + 0 + + + + Indicate that read/write value is a floating point number. Overrides unsigned flag. + false + + + + Value assumed for increase/decrease command. + 5 + + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + + + + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter16-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter16-channel-config.xml index fffde168..086a56b6 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter16-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter16-channel-config.xml @@ -115,6 +115,11 @@ false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter32-channel-config.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter32-channel-config.xml index 098750c3..81c8ac2a 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter32-channel-config.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/config/rollershutter32-channel-config.xml @@ -115,6 +115,11 @@ false + + + Time between next poll cycles, 0 assumes same value as Thing for which this channel is defined. + 0 + diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/channels.xml index f580517f..84e77311 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/channels.xml @@ -21,10 +21,17 @@ 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"> + + Contact + + A read only channel which represent state of input or output. + + + Switch - - Discrete register of connected PLC. + + Discrete register of connected PLC which can be commanded. @@ -41,6 +48,21 @@ + + Dimmer + + Data register for representing percentage expressed as integer (0 ... 100) based on 16 bit register. + + + + + Dimmer + + Data register for representing percentage in range as integer or floating point number based on 32 bit register. + + + + Rollershutter diff --git a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/thing.xml b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/thing.xml index 4016efd5..3605df66 100644 --- a/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/thing.xml +++ b/bundles/org.connectorio.addons.binding.fatek/src/main/resources/OH-INF/thing/thing.xml @@ -23,7 +23,7 @@ https://openhab.org/schemas/thing-description-1.0.0.xsd "> - +