diff --git a/bundles/org.smarthomej.binding.knx/NOTICE b/bundles/org.smarthomej.binding.knx/NOTICE deleted file mode 100644 index 68e64ecfc4..0000000000 --- a/bundles/org.smarthomej.binding.knx/NOTICE +++ /dev/null @@ -1,15 +0,0 @@ -This content is produced and maintained by the SmartHome/J project. - -* Project home: https://www.smarthomej.org - -== Declared Project Licenses - -This program and the accompanying materials are made available under the terms -of the Eclipse Public License 2.0 which is available at -https://www.eclipse.org/legal/epl-2.0/. - -== Source Code - -https://github.com/smarthomej/addons - -Parts of this code have been forked from https://github.com/openhab/openhab-addons \ No newline at end of file diff --git a/bundles/org.smarthomej.binding.knx/README.md b/bundles/org.smarthomej.binding.knx/README.md deleted file mode 100644 index 0b50f6d70b..0000000000 --- a/bundles/org.smarthomej.binding.knx/README.md +++ /dev/null @@ -1,334 +0,0 @@ -# KNX Binding - -The openHAB KNX binding allows to connect to [KNX Home Automation](https://www.knx.org/) installations. -Switching lights on and off, activating your roller shutters or changing room temperatures are only some examples. - -To access your KNX bus you either need a gateway device which is connected to the KNX bus and allows computers to access the bus communication. -This can be either an Ethernet (as a Router or a Tunnel type) or a serial gateway. -The KNX binding then can communicate directly with this gateway. -Alternatively a PC running [KNXD](https://github.com/knxd/knxd) (free open source component software) can be put in between which then acts as a broker allowing multiple client to connect to the same gateway. -Since the protocol is identical, the KNX binding can also communicate with it transparently. - -***Attention:*** With the introduction of UoM support in version 3.2.7 (see `number` channel below) some data types have changed: - -- the data type for DPT 5.001 (Percent 8bit, 0 -> 100%) has changed from `PercentType` to `QuantityType` for `number` channels (`dimmer`, `color`, `rollershutter` channels stay with `PercentType`) -- the data type for DPT 5.004 (Percent 8bit, 0 -> 255%) has changed from `PercentType` to `QuantityType` -- the data type for DPT 6.001 (Percent 8bit -128 -> 127%) has changed from `PercentType` to `QuantityType` -- the data type for DPT 9.007 (Humidity) has changed from `PercentType` to `QuantityType` - -Rules that check for or compare states and transformations that expect a raw value might need adjustments. -If you run into trouble with that and need some time, you can disable UoM support on binding level via the `disableUoM` parameter. -UoM are enabled by default and need to be disabled manually. -A new setting is activated immediately without restart. - -## Supported Things - -The KNX binding supports two types of bridges, and one type of things to access the KNX bus. -There is an *ip* bridge to connect to KNX IP Gateways, and a *serial* bridge for connection over a serial port to a host-attached gateway. - -## Bridges - -The following two bridge types are supported. -Bridges don't have channels on their own. - -### IP Gateway - -The IP Gateway is the most commonly used way to connect to the KNX bus. At its base, the *ip* bridge accepts the following configuration parameters: - -| Name | Required | Description | Default value | -|---------------------|--------------|--------------------------------------------------------------------------------------------------------------|------------------------------------------------------| -| type | Yes | The IP connection type for connecting to the KNX bus (`TUNNEL` or `ROUTER`) | - | -| ipAddress | for `TUNNEL` | Network address of the KNX/IP gateway. If type `ROUTER` is set, the IPv4 Multicast Address can be set. | for `TUNNEL`: \, for `ROUTER`: 224.0.23.12 | -| portNumber | for `TUNNEL` | Port number of the KNX/IP gateway | 3671 | -| localIp | No | Network address of the local host to be used to set up the connection to the KNX/IP gateway | the system-wide configured primary interface address | -| localSourceAddr | No | The (virtual) individual address for identification of this KNX/IP gateway within the KNX bus

Note: Use a free adress, not the one of the interface. Or leave it at `0.0.0` and let openHAB decide which address to use. | 0.0.0 | -| useNAT | No | Whether there is network address translation between the server and the gateway | false | -| readingPause | No | Time in milliseconds of how long should be paused between two read requests to the bus during initialization | 50 | -| responseTimeout | No | Timeout in seconds to wait for a response from the KNX bus | 10 | -| readRetriesLimit | No | Limits the read retries while initialization from the KNX bus | 3 | -| autoReconnectPeriod | No | Seconds between connect retries when KNX link has been lost (0 means never). | 0 | - - -### Serial Gateway - -The *serial* bridge accepts the following configuration parameters: - -| Name | Required | Description | Default value | -|---------------------|----------|--------------------------------------------------------------------------------------------------------------|---------------| -| serialPort | Y | The serial port to use for connecting to the KNX bus | - | -| readingPause | N | Time in milliseconds of how long should be paused between two read requests to the bus during initialization | 50 | -| responseTimeout | N | Timeout in seconds to wait for a response from the KNX bus | 10 | -| readRetriesLimit | N | Limits the read retries while initialization from the KNX bus | 3 | -| autoReconnectPeriod | N | Seconds between connect retries when KNX link has been lost, 0 means never retry | 0 | - -## Things - -### *device* Things - -*basic* Things are wrappers around an arbitrary group addresses on the KNX bus. -They have no specific function in the KNX binding, except that if the *address* is defined the binding will actively poll the Individual Address on the KNX bus to detect that the KNX actuator is reachable. -Under normal real world circumstances, either all devices on a bus are reachable, or the entire bus is down. -When *fetch* is set to true, the binding will read-out the memory of the KNX actuator in order to detect configuration data and so forth. -This is however an experimental feature very prone to the actual on the KNX bus. - -| Name | Required | Description | Default value | -|--------------|----------|--------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| -| address | N | The individual device address (in 0.0.0 notation) | - | -| fetch | N | Read out the device parameters and address/communication object tables (requires the address) | false | -| pingInterval | N | Interval (in seconds) to contact the device and set the thing status based on the result (requires the address) | 600 | -| readInterval | N | Interval (in seconds) to actively request reading of values from the bus (0 if they should only be read once at startup) | 0 | - -Different kinds of channels are defined and can be used to group together Group Addresses. -All channel types share two configuration parameters: *read*, an optional parameter to indicate if the 'readable' group addresses of that Channel should be read at startup (default: false), and *interval*, an optional parameter that defines an interval between attempts to read the status group address on the bus, in seconds. -When defined and set to 0, the interval is ignored (default: 0) - -#### Channel Types - -Standard channels are used most of the time. -They are used in the common case where the physical state is owned by a device within the KNX bus, e.g. by a switch actuator who "knows" whether the light is turned on or of or by a temperature sensor which reports the room temperature regularly. - -Control channel types (suffix `-control`) are used for cases where the KNX bus does not own the physical state of a device. -This could be the case if e.g. a lamp from another binding should be controlled by a KNX wall switch. -If from the KNX bus a `GroupValueRead` telegram is sent to a *-control Channel, the bridge responds with a `GroupValueResponse` telegram to the KNX bus. - -##### Channel Type `color`, `color-control` - -| Parameter | Description | Default DPT | -|------------------|----------------------------------------|-------------| -| hsb | Group address for the color | 232.600 | -| switch | Group address for the binary switch | 1.001 | -| position | Group address brightness | 5.001 | -| increaseDecrease | Group address for relative brightness | 3.007 | - -The `hsb` address supports DPT 242.600 and 251.600. - -Some RGB/RGBW products (e.g. MDT) support HSB values for DPT 232.600 instead of RGB. -This is supported as "vendor-specific DPT" with a value of 232.60000. - -##### Channel Type `contact`, `contact-control` - -| Parameter | Description | Default DPT | -|-----------|---------------|-------------| -| ga | Group address | 1.009 | - -*Attention:* Due to a bug in the original implementation the states for DPT 1.009 are inverted (i.e. `1` is mapped to `OPEN` instead of `CLOSE`). -A change would break all existing installations and is therefore not implemented. - -##### Channel Type `datetime`, `datetime-control` - -| Parameter | Description | Default DPT | -|-----------|---------------|-------------| -| ga | Group address | 19.001 | - -##### Channel Type `dimmer`, `dimmer-control` - -| Parameter | Description | Default DPT | -|------------------|----------------------------------------|-------------| -| switch | Group address for the binary switch | 1.001 | -| position | Group address of the brightness | 5.001 | -| increaseDecrease | Group address for relative brightness | 3.007 | - -##### Channel Type `number`, `number-control` - -| Parameter | Description | Default DPT | -|-----------|---------------|-------------| -| ga | Group address | 9.001 | - -The `number` channel has full support for UoM. - -Incoming values from the KNX bus are converted to values with units (e.g. `23 °C`). -If the channel is linked to the correct item-type (`Number:Temperature` in this case) the display unit can be controlled my item metadata (e.g. `%.1f °F` for 1 digit of precision in Fahrenheit). -The unit is stripped if the channel is linked to a plain number item (type `Number`). - -Outgoing values with unit are first converted to the unit associated with the DPT (e.g. a value of `10 °F` is converted to `-8.33 °C` if the channel has DPT 9.001). -Values from plain number channels are sent as-is (without any conversion). - -##### Channel Type `rollershutter`, `rollershutter-control` - -| Parameter | Description | Default DPT | -|-----------|-----------------------------------------|-------------| -| upDown | Group address for relative movement | 1.008 | -| stopMove | Group address for stopping | 1.010 | -| position | Group address for the absolute position | 5.001 | - -##### Channel Type `string`, `string-control` - -| Parameter | Description | Default DPT | -|-----------|---------------|-------------| -| ga | Group address | 16.001 | - -##### Channel Type `switch`, `switch-control` - -| Parameter | Description | Default DPT | -|-----------|-------------------------------------|-------------| -| ga | Group address for the binary switch | 1.001 | - -#### Group Address Notation - -``` -="[:][<][[+[<]][+[<]..]]" -``` - -where parts in brackets `[]` denote optional information. - -The optional `<` sign tells whether the group address of the datapoint accepts read requests on the KNX bus (it does, if the sign is there). -With `*-control` channels, the state is not owned by any device on the KNX bus, therefore no read requests will be sent by the binding, i.e. `<` signs will be ignored for them. - -Each configuration parameter has a `mainGA` where commands are written to and optionally several `listeningGA`s. - -The `dpt` element is optional. If ommitted, the corresponding default value will be used (see the channel descriptions above). - - -## Examples - -The following two templates are sufficient for almost all purposes. -Only add parameters to the Bridge and Thing configuration if you know exactly what functionality it is needed for. - -### Type ROUTER mode configuration Template - -knx.things: - -```xtend -Bridge knx:ip:bridge [ - type="ROUTER", - autoReconnectPeriod=60 //optional, do not set <30 sec. -] { - Thing device knx_device "knx_device_name" @ "knx_device_group" [ - //readInterval=3600 //optional, only used if reading values are present - ] { - //Items configurations - } -} -``` - -### Type TUNNEL mode configuration Template - -knx.things: - -```xtend -Bridge knx:ip:bridge [ - type="TUNNEL", - ipAddress="192.168.0.111", - autoReconnectPeriod=60 //optional, do not set <30 sec. -] { - Thing device knx_device "knx_device_name" @ "knx_device_group" [ - //readInterval=3600 //optional, only used if reading values are present - ] { - //Items configurations - } -} -``` - -### Full Example - -```xtend -//TUNNEL -Bridge knx:ip:bridge [ - type="TUNNEL", - ipAddress="192.168.0.10", - portNumber=3671, - localIp="192.168.0.11", - readingPause=50, - responseTimeout=10, - readRetriesLimit=3, - autoReconnectPeriod=60, - localSourceAddr="0.0.0" -] { - Thing device generic [ - address="1.2.3", - fetch=true, - pingInterval=300, - readInterval=3600 - ] { - Type color : demoColor "Color" [ hsb="251.600:3/7/10" ] - Type switch : demoSwitch "Light" [ ga="3/0/4+<3/0/5" ] - Type rollershutter : demoRollershutter "Shade" [ upDown="4/3/50+4/3/51", stopMove="4/3/52+4/3/53", position="4/3/54+<4/3/55" ] - Type contact : demoContact "Door" [ ga="1.019:<5/1/2" ] - Type number : demoTemperature "Temperature" [ ga="9.001:<5/0/0" ] - Type dimmer : demoDimmer "Dimmer" [ switch="5/0/0+<5/0/1", position="5/0/2+<5/0/3", increaseDecrease="5/0/4" ] - Type string : demoString "Message" [ ga="5/3/1" ] - Type datetime : demoDatetime "Alarm" [ ga="5/5/42" ] - } -} - -//ROUTER -Bridge knx:ip:bridge [ - type="ROUTER", - ipAddress="224.0.23.12", - portNumber=3671, - localIp="192.168.0.11", - readingPause=50, - responseTimeout=10, - readRetriesLimit=3, - autoReconnectPeriod=60, - localSourceAddr="0.0.0" -] {} -``` - -knx.items: - -```xtend -Color demoColor "Color [%s]" { channel="knx:device:bridge:generic:demoColor" } -Switch demoSwitch "Light [%s]" { channel="knx:device:bridge:generic:demoSwitch" } -Dimmer demoDimmer "Dimmer [%d %%]" { channel="knx:device:bridge:generic:demoDimmer" } -Rollershutter demoRollershutter "Shade [%d %%]" { channel="knx:device:bridge:generic:demoRollershutter" } -Contact demoContact "Front Door [%s]" { channel="knx:device:bridge:generic:demoContact" } -Number:Temperature demoTemperature "Temperature [%.1f °F]" { channel="knx:device:bridge:generic:demoTemperature" } -String demoString "Message of the day [%s]" { channel="knx:device:bridge:generic:demoString" } -DateTime demoDatetime "Alarm [%1$tH:%1$tM]" { channel="knx:device:bridge:generic:demoDatetime" } -``` - -knx.sitemap: - -```xtend -sitemap knx label="KNX Demo Sitemap" { - Frame label="Demo Elements" { - Colorpicker item=demoColor - Switch item=demoSwitch - Switch item=demoRollershutter - Text item=demoContact - Text item=demoTemperature - Slider item=demoDimmer - Text item=demoString - Text item=demoDatetime - } -} - -``` - -### Control Example - -control.things: - -```xtend -Bridge knx:serial:bridge [ - serialPort="/dev/ttyAMA0", - readingPause=50, - responseTimeout=10, - readRetriesLimit=3, - autoReconnectPeriod=60 -] { - Thing device generic { - Type switch-control : controlSwitch "Control Switch" [ ga="3/3/10+<3/3/11" ] // '<' signs are allowed but will be ignored for control Channels - Type dimmer-control : controlDimmer "Control Dimmer" [ switch="3/3/50+3/3/48", position="3/3/46", increaseDecrease="3/3/49", frequency=300 ] - Type rollershutter-control : controlRollershutter "Control Rollershutter" [ upDown="3/4/1+3/4/2", stopMove="3/4/3", position="3/4/4" ] - Type number-control : controlNumber "Control Number" [ ga="1/2/2" ] - Type string-control : controlString "Control String" [ ga="1/4/2" ] - Type datetime-control : controlDatetime "Control Datetime" [ ga="5/1/30" ] - } -} - -Bridge hue:bridge:bridge "Philips Hue Bridge" [ - ipAddress="...", - userName="..." -] { - Thing 0210 1 "Color Lamp" [ lightId="1" ] -} -``` - -knx.items: - -```xtend -Switch demoSwitch "Light [%s]" { channel="hue:0210:bridge:1:color", channel="knx:device:bridge:generic:controlSwitch" } -Dimmer demoDimmer "Dimmer [%d %%]" { channel="hue:0210:bridge:1:color", channel="knx:device:bridge:generic:controlDimmer" } -``` diff --git a/bundles/org.smarthomej.binding.knx/doc/dpt.list b/bundles/org.smarthomej.binding.knx/doc/dpt.list deleted file mode 100644 index e2a89355e9..0000000000 --- a/bundles/org.smarthomej.binding.knx/doc/dpt.list +++ /dev/null @@ -1,320 +0,0 @@ -MainType: 1 -1.000: General bool -1.001: DPT_Switch values: 0 = off 1 = on -1.002: DPT_Bool values: 0 = false 1 = true -1.003: DPT_Enable values: 0 = disable 1 = enable -1.004: DPT_Ramp values: 0 = no ramp 1 = ramp -1.005: DPT_Alarm values: 0 = no alarm 1 = alarm -1.006: DPT_BinaryValue values: 0 = low 1 = high -1.007: DPT_Step values: 0 = decrease 1 = increase -1.008: DPT_UpDown values: 0 = up 1 = down -1.009: DPT_OpenClose values: 0 = open 1 = close -1.010: DPT_Start values: 0 = stop 1 = start -1.011: DPT_State values: 0 = inactive 1 = active -1.012: DPT_Invert values: 0 = not inverted 1 = inverted -1.013: DPT_DimSendStyle values: 0 = start/stop 1 = cyclic -1.014: DPT_InputSource values: 0 = fixed 1 = calculated -1.015: DPT_Reset values: 0 = no action 1 = reset -1.016: DPT_Ack values: 0 = no action 1 = acknowledge -1.017: DPT_Trigger values: 0 = trigger 1 = trigger -1.018: DPT_Occupancy values: 0 = not occupied 1 = occupied -1.019: DPT_Window_Door values: 0 = closed 1 = open -1.021: DPT_LogicalFunction values: 0 = OR 1 = AND -1.022: DPT_Scene_AB values: 0 = scene A 1 = scene B -1.023: DPT_ShutterBlinds_Mode values: 0 = only move up/down 1 = move up/down + step-stop -1.100: DPT_Heat/Cool values: 0 = cooling 1 = heating - -MainType: 2 -2.001: DPT_Switch_Control values: 0 = off 1 = on -2.002: DPT_Bool_Control values: 0 = false 1 = true -2.003: DPT_Enable_Control values: 0 = disable 1 = enable -2.004: DPT_Ramp_Control values: 0 = no ramp 1 = ramp -2.005: DPT_Alarm_Control values: 0 = no alarm 1 = alarm -2.006: DPT_BinaryValue_Control values: 0 = low 1 = high -2.007: DPT_Step_Control values: 0 = decrease 1 = increase -2.008: DPT_Direction1_Control values: 0 = up 1 = down -2.009: DPT_Direction2_Control values: 0 = open 1 = close -2.010: DPT_Start_Control values: 0 = stop 1 = start -2.011: DPT_State_Control values: 0 = inactive 1 = active -2.012: DPT_Invert_Control values: 0 = not inverted 1 = inverted - -MainType: 3 -3.007: DPT_Control_Dimming values: 0 = decrease 1 = increase -3.008: DPT_Control_Blinds values: 0 = up 1 = down - -MainType: 4 -4.001: DPT_Char_ASCII -4.002: DPT_Char_8859_1 - -MainType: 5 -5.000: General byte -5.001: DPT_Scaling values: 0...100 % -5.003: DPT_Angle values: 0...360 ° -5.004: DPT_Percent_U8 (8 Bit) values: 0...255 % -5.005: DPT_DecimalFactor values: 0...255 ratio -5.006: DPT_Tariff values: 0...254 -5.010: DPT_Value_1_Ucount Unsigned count values: 0...255 counter pulses - -MainType: 6 -6.001: DPT_Percent_V8 (8 Bit) values: -128...127 % -6.010: DPT_Value_1_Count values: signed -128...127 counter pulses -6.020: DPT_Status_Mode3 with mode values: 0/0/0/0/0 0...1/1/1/1/1 2 - -MainType: 7 -7.000: General unsigned integer -7.001: DPT_Value_2_Ucount values: 0...65535 pulses -7.002: DPT_TimePeriodMsec values: 0...65535 res 1 ms -7.003: DPT_TimePeriod10MSec values: 0...655350 res 10 ms -7.004: DPT_TimePeriod100MSec values: 0...6553500 res 100 ms -7.005: DPT_TimePeriodSec values: 0...65535 s -7.006: DPT_TimePeriodMin values: 0...65535 min -7.007: DPT_TimePeriodHrs values: 0...65535 h -7.010: DPT_PropDataType values: 0...65535 -7.011: DPT_Length_mm values: 0...65535 mm -7.012: DPT_UElCurrentmA values: 0...65535 mA -7.013: DPT_Brightness values: 0...65535 lx -Calimero does not map: (map/use to 7.000 until then) -7.600: DPT_Colour_Temperature values: 0...65535 K, 2000K 3000K 5000K 8000K - -MainType: 8 -8.000: General integer -8.001: DPT_Value_2_Count -8.002: DPT_DeltaTimeMsec -8.003: DPT_DeltaTime10MSec -8.004: DPT_DeltaTime100MSec -8.005: DPT_DeltaTimeSec -8.006: DPT_DeltaTimeMin -8.007: DPT_DeltaTimeHrs -8.010: DPT_Percent_V16 -8.011: DPT_Rotation_Angle - -MainType: 9 -9.000: General float -9.001: DPT_Value_Temp values: -273...+670760 °C -9.002: DPT_Value_Tempd values: -670760...+670760 K -9.003: DPT_Value_Tempa values: -670760...+670760 K/h -9.004: DPT_Value_Lux values: 0...+670760 lx -9.005: DPT_Value_Wsp values: 0...+670760 m/s -9.006: DPT_Value_Pres values: 0...+670760 Pa -9.007: DPT_Value_Humidity values: 0...+670760 % -9.008: DPT_Value_AirQuality values: 0...+670760 ppm -9.010: DPT_Value_Time1 values: -670760...+670760 s -9.011: DPT_Value_Time2 values: -670760...+670760 ms -9.020: DPT_Value_Volt values: -670760...+670760 mV -9.021: DPT_Value_Curr values: -670760...+670760 mA -9.022: DPT_PowerDensity values: -670760...+670760 W/m² -9.023: DPT_KelvinPerPercent values: -670760...+670760 K/% -9.024: DPT_Power values: -670760...+670760 kW -9.025: DPT_Value_Volume_Flow values: -670760...+670760 l/h -9.026: DPT_Rain_Amount values: -671088.64...670760.96 l/m² -9.027: DPT_Value_Temp_F values: -459.6...670760.96 °F -9.028: DPT_Value_Wsp_kmh values: 0...670760.96 km/h - -MainType: 10 -10.001: DPT_TimeOfDay values: 1 = Monday...7 = Sunday, 0 = no-day, 00:00:00 Sun, 23:59:59 dow, hh:mm:ss - -MainType: 11 -11.001: DPT_Date values: 1990-01-01...2089-12-31, yyyy-mm-dd - -MainType: 12 -12.000: General unsigned long -12.001: DPT_Value_4_Ucount values: 0...4294967295 counter pulses - -MainType: 13 -13.000: General long -13.001: DPT_Value_4_Count values: -2147483648...2147483647 counter pulses -13.002: DPT_FlowRate_m3h values: -2147483648...2147483647 m3/h -13.010: DPT_ActiveEnergy values: -2147483648...2147483647 Wh -13.011: DPT_ApparantEnergy values: -2147483648...2147483647 VAh -13.012: DPT_ReactiveEnergy values: -2147483648...2147483647 VARh -13.013: DPT_ActiveEnergy_kWh values: -2147483648...2147483647 kWh -13.014: DPT_ApparantEnergy_kVAh values: -2147483648...2147483647 kVAh -13.015: DPT_ReactiveEnergy_kVARh values: -2147483648...2147483647 kVAR -13.100: DPT_LongDeltaTimeSec values: -2147483648...2147483647 s - -MainType: 14, Range: [-3.40282347e+38f...3.40282347e+38f] -14.000: Acceleration, values: ms⁻² -14.001: Acceleration, angular, values: rad s⁻² -14.002: Activation energy, values: J/mol -14.003: Activity, values: s⁻¹ -14.004: Mol, values: mol -14.005: Amplitude, values: -14.006: Angle, values: rad -14.007: Angle, values: ° -14.008: Momentum, values: Js -14.009: Angular velocity, values: rad/s -14.010: Area, values: m² -14.011: Capacitance, values: F -14.012: Charge density (surface), values: C m⁻² -14.013: Charge density (volume), values: C m⁻³ -14.014: Compressibility, values: m²/N -14.015: Conductance, values: Ω⁻¹ -14.016: Conductivity, electrical, values: Ω⁻¹m⁻¹ -14.017: Density, values: kg m⁻³ -14.018: Electric charge, values: C -14.019: Electric current, values: A -14.020: Electric current density, values: A m⁻² -14.021: Electric dipole moment, values: Cm -14.022: Electric displacement, values: C m⁻² -14.023: Electric field strength, values: V/m -14.024: Electric flux, values: Vm -14.025: Electric flux density, values: C m⁻² -14.026: Electric polarization, values: C m⁻² -14.027: Electric potential, values: V -14.028: Electric potential difference, values: V -14.029: Electromagnetic moment, values: A m² -14.030: Electromotive force, values: V -14.031: Energy, values: J -14.032: Force, values: N -14.033: Frequency, values: Hz -14.034: Frequency, angular, values: rad/s -14.035: Heat capacity, values: J/K -14.036: Heat flow rate, values: W -14.037: Heat quantity, values: J -14.038: Impedance, values: Ω -14.039: Length, values: m -14.040: Quantity of Light, values: J -14.041: Luminance, values: cd m⁻² -14.042: Luminous flux, values: lm -14.043: Luminous intensity, values: cd -14.044: Magnetic field strength, values: A/m -14.045: Magnetic flux, values: Wb -14.046: Magnetic flux density, values: T -14.047: Magnetic moment, values: A m² -14.048: Magnetic polarization, values: T -14.049: Magnetization, values: A/m -14.050: Magneto motive force, values: A -14.051: Mass, values: kg -14.052: Mass flux, values: kg/s -14.053: Momentum, values: N/s -14.054: Phase angle, radiant, values: rad -14.055: Phase angle, degree, values: ° -14.056: Power, values: W -14.057: Power factor, values: -14.058: Pressure, values: Pa -14.059: Reactance, values: Ω -14.060: Resistance, values: Ω -14.061: Resistivity, values: Ωm -14.062: Self inductance, values: H -14.063: Solid angle, values: sr -14.064: Sound intensity, values: W m⁻² -14.065: Speed, values: m/s -14.066: Stress, values: Pa -14.067: Surface tension, values: N/m -14.068: Temperature in Celsius Degree, values: °C -14.069: Temperature, absolute, values: K -14.070: Temperature difference, values: K -14.071: Thermal capacity, values: J/K -14.072: Thermal conductivity, values: W/m K⁻¹ -14.073: Thermoelectric power, values: V/K -14.074: Time, values: s -14.075: Torque, values: Nm -14.076: Volume, values: m³ -14.077: Volume flux, values: m³/s -14.078: Weight, values: N -14.079: Work, values: J - -MainType: 16 -16.000: ASCII string -16.001: ISO-8859-1 string (Latin 1) - -MainType: 17 -17.001: Scene Number, values: 0...63 - -MainType: 18 -18.001: Scene Control, values: 0...63, 0 = activate, 1 = learn - -MainType: 19 -19.001: Date with time, values: 0 = 1900, 255 = 2155, 01/01 00:00:00, 12/31 24:00:00 yr/mth/day hr:min:sec - -MainType: 20 -20.001: System Clock Mode, enumeration [0..2] -20.002: Building Mode, enumeration [0..2] -20.003: Occupancy Mode, enumeration [0..2] -20.004: Priority, enumeration [0..3] -20.005: Light Application Mode, enumeration [0..2] -20.006: Application Area, enumeration [0..14] -20.007: Alarm Class Type, enumeration [0..3] -20.008: PSU Mode, enumeration [0..2] -20.011: Error Class System, enumeration [0..18] -20.012: Error Class HVAC, enumeration [0..4] -20.013: Time Delay, enumeration [0..25] -20.014: Beaufort Wind Force Scale, enumeration [0..12] -20.017: Sensor Select, enumeration [0..4] -20.020: Actuator Connect Type, enumeration [1..2] -20.100: Fuel Type, enumeration [0..3] -20.101: Burner Type, enumeration [0..3] -20.102: HVAC Mode, enumeration [0..4] -20.103: DHW Mode, enumeration [0..4] -20.104: Load Priority, enumeration [0..2] -20.105: HVAC Control Mode, enumeration [0..20] -20.106: HVAC Emergency Mode, enumeration [0..5] -20.107: Changeover Mode, enumeration [0..2] -20.108: Valve Mode, enumeration [1..5] -20.109: Damper Mode, enumeration [1..4] -20.110: Heater Mode, enumeration [1..3] -20.111: Fan Mode, enumeration [0..2] -20.112: Master/Slave Mode, enumeration [0..2] -20.113: Status Room Setpoint, enumeration [0..2] -20.114: Metering Device Type, enumeration [0..41/255] -20.120: Air Damper Actuator Type, enumeration [1..2] -20.121: Backup Mode, enumeration [0..1] -20.122: Start Synchronization, enumeration [0..2] -20.600: Behavior Lock/Unlock, enumeration [0..6] -20.601: Behavior Bus Power Up/Down, enumeration [0..4] -20.602: DALI Fade Time, enumeration [0..15] -20.603: Blinking Mode, enumeration [0..2] -20.604: Light Control Mode, enumeration [0..1] -20.605: Switch PB Model, enumeration [1..2] -20.606: PB Action, enumeration [0..3] -20.607: Dimm PB Model, enumeration [1..4] -20.608: Switch On Mode, enumeration [0..2] -20.609: Load Type Set, enumeration [0..2] -20.610: Load Type Detected, enumeration [0..3] -20.801: SAB Except Behavior, enumeration [0..4] -20.802: SAB Behavior Lock/Unlock, enumeration [0..6] -20.803: SSSB Mode, enumeration [1..4] -20.804: Blinds Control Mode, enumeration [0..1] -20.1000: Comm Mode, enumeration [0..255] -20.1001: Additional Info Type, enumeration [0..7] -20.1002: RF Mode Select, enumeration [0..2] -20.1003: RF Filter Select, enumeration [0..3] -20.1200: M-Bus Breaker/Valve State, enumeration [0..255] -20.1202: Gas Measurement Condition, enumeration [0..3] - -MainType: 21 -21.001: General Status, values: 0...31 -21.002: Device Control, values: 0...7 -21.100: Forcing Signal, values: 0...255 -21.101: Forcing Signal Cool, values: 0...1 -21.102: Room Heating Controller Status, values: 0...255 -21.103: Solar Dhw Controller Status, values: 0...7 -21.104: Fuel Type Set, values: 0...7 -21.105: Room Cooling Controller Status, values: 0...1 -21.106: Ventilation Controller Status, values: 0...15 -21.601: Light Actuator Error Info, values: 0...127 -21.1000: R F Comm Mode Info, values: 0...7 -21.1001: R F Filter Modes, values: 0...7 -21.1010: Channel Activation State, values: 0...255 - -MainType: 22 -unsupported: 22.100: DHW Controller Status -22.101: RHCC Status (enumeration) -unsupported: 22.102: HVAC combined status -unsupported: 22.103: RTC status -22.1000: KNX medium (enumeration) -unsupported: 22.1010: 16 channel activation - -MainType: 28 -28.001: UTF-8 - -MainType: 29 -29.010: Active Energy, values: -9223372036854775808...9223372036854775807 Wh -29.011: Apparent energy, values: -9223372036854775808...9223372036854775807 VAh -29.012: Reactive energy, values: -9223372036854775808...9223372036854775807 VARh - -MainType: 229 -229.001: Metering Value, values: -2147483648...2147483647 - -MainType: 232, 3 bytes -232.600: DPT_Colour_RGB, values: 0 0 0...255 255 255, r g b diff --git a/bundles/org.smarthomej.binding.knx/pom.xml b/bundles/org.smarthomej.binding.knx/pom.xml deleted file mode 100644 index a7fa33f158..0000000000 --- a/bundles/org.smarthomej.binding.knx/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - 4.0.0 - - - org.smarthomej.addons.bundles - org.smarthomej.addons.reactor.bundles - 4.0.0-SNAPSHOT - - - org.smarthomej.binding.knx - - SmartHome/J Add-ons :: Bundles :: KNX Binding - - - gnu.io;version="[3.12,6)",javax.microedition.io.*;resolution:="optional",javax.usb.*;resolution:="optional",org.usb4java.*;resolution:="optional" - 2.5 - - - - - com.github.calimero - calimero-core - ${calimero.version} - compile - - - org.slf4j - slf4j-api - - - - - com.github.calimero - calimero-device - ${calimero.version} - compile - - - org.slf4j - slf4j-api - - - - - com.github.calimero - calimero-rxtx - ${calimero.version} - compile - - - org.slf4j - slf4j-api - - - - - org.smarthomej.addons.bundles - org.smarthomej.commons - ${project.version} - provided - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/feature/feature.xml b/bundles/org.smarthomej.binding.knx/src/main/feature/feature.xml deleted file mode 100644 index 88d467baa0..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/feature/feature.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - openhab-runtime-base - openhab-transport-serial - mvn:org.smarthomej.addons.bundles/org.smarthomej.commons/${project.version} - mvn:org.smarthomej.addons.bundles/org.smarthomej.binding.knx/${project.version} - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/KNXBindingConstants.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/KNXBindingConstants.java deleted file mode 100644 index 8ff2d299d4..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/KNXBindingConstants.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.ThingTypeUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.commons.util.ResourceUtil; - -/** - * The {@link KNXBindingConstants} class defines common constants, which are - * used across the whole binding. - * - * @author Karel Goderis - Initial contribution - */ -@NonNullByDefault -public class KNXBindingConstants { - private static final Logger LOGGER = LoggerFactory.getLogger(KNXBindingConstants.class); - - public static final String BINDING_ID = "knx"; - - // Global config - public static final String CONFIG_DISABLE_UOM = "disableUoM"; - public static boolean DISABLE_UOM = false; - - // Thing Type UIDs - public static final ThingTypeUID THING_TYPE_IP_BRIDGE = new ThingTypeUID(BINDING_ID, "ip"); - public static final ThingTypeUID THING_TYPE_SERIAL_BRIDGE = new ThingTypeUID(BINDING_ID, "serial"); - public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device"); - - // Property IDs - public static final String FIRMWARE_TYPE = "firmwaretype"; - public static final String FIRMWARE_VERSION = "firmwareversion"; - public static final String FIRMWARE_SUBVERSION = "firmwaresubversion"; - public static final String MANUFACTURER_NAME = "manfacturername"; - public static final String MANUFACTURER_SERIAL_NO = "manfacturerserialnumber"; - public static final String MANUFACTURER_HARDWARE_TYPE = "manfacturerhardwaretype"; - public static final String MANUFACTURER_FIRMWARE_REVISION = "manfacturerfirmwarerevision"; - - // Thing Configuration parameters - public static final String IP_ADDRESS = "ipAddress"; - public static final String IP_CONNECTION_TYPE = "type"; - public static final String LOCAL_IP = "localIp"; - public static final String LOCAL_SOURCE_ADDRESS = "localSourceAddr"; - public static final String PORT_NUMBER = "portNumber"; - public static final String SERIAL_PORT = "serialPort"; - - // The default multicast ip address (see iana EIBnet/IP - public static final String DEFAULT_MULTICAST_IP = "224.0.23.12"; - - // Channel Type IDs - public static final String CHANNEL_COLOR = "color"; - public static final String CHANNEL_COLOR_CONTROL = "color-control"; - public static final String CHANNEL_CONTACT = "contact"; - public static final String CHANNEL_CONTACT_CONTROL = "contact-control"; - public static final String CHANNEL_DATETIME = "datetime"; - public static final String CHANNEL_DATETIME_CONTROL = "datetime-control"; - public static final String CHANNEL_DIMMER = "dimmer"; - public static final String CHANNEL_DIMMER_CONTROL = "dimmer-control"; - public static final String CHANNEL_NUMBER = "number"; - public static final String CHANNEL_NUMBER_CONTROL = "number-control"; - public static final String CHANNEL_ROLLERSHUTTER = "rollershutter"; - public static final String CHANNEL_ROLLERSHUTTER_CONTROL = "rollershutter-control"; - public static final String CHANNEL_STRING = "string"; - public static final String CHANNEL_STRING_CONTROL = "string-control"; - public static final String CHANNEL_SWITCH = "switch"; - public static final String CHANNEL_SWITCH_CONTROL = "switch-control"; - - public static final Set CONTROL_CHANNEL_TYPES = Set.of( // - CHANNEL_COLOR_CONTROL, // - CHANNEL_CONTACT_CONTROL, // - CHANNEL_DATETIME_CONTROL, // - CHANNEL_DIMMER_CONTROL, // - CHANNEL_NUMBER_CONTROL, // - CHANNEL_ROLLERSHUTTER_CONTROL, // - CHANNEL_STRING_CONTROL, // - CHANNEL_SWITCH_CONTROL // - ); - - public static final String CHANNEL_RESET = "reset"; - - // Channel Configuration parameters - public static final String GA = "ga"; - public static final String HSB_GA = "hsb"; - public static final String INCREASE_DECREASE_GA = "increaseDecrease"; - public static final String POSITION_GA = "position"; - public static final String REPEAT_FREQUENCY = "frequency"; - public static final String STOP_MOVE_GA = "stopMove"; - public static final String SWITCH_GA = "switch"; - public static final String UP_DOWN_GA = "upDown"; - - public static final Map MANUFACTURER_MAP = ResourceUtil - .readProperties(KNXBindingConstants.class, "manufacturer.properties").entrySet().stream() - .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey()), Map.Entry::getValue)); - public static final Map FIRMWARE_MAP = ResourceUtil - .readProperties(KNXBindingConstants.class, "firmware.properties").entrySet().stream() - .collect(Collectors.toMap(e -> Integer.parseInt(e.getKey()), Map.Entry::getValue)); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/GroupAddressConfiguration.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/GroupAddressConfiguration.java deleted file mode 100644 index 9b740756fd..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/GroupAddressConfiguration.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.KNXFormatException; - -/** - * Data structure representing the content of a channel's group address configuration. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class GroupAddressConfiguration { - public static final Logger LOGGER = LoggerFactory.getLogger(GroupAddressConfiguration.class); - - private static final Pattern PATTERN_GA_CONFIGURATION = Pattern.compile( - "^((?[1-9][0-9]{0,2}\\.[0-9]{3,5}):)?(?<)?(?[0-9]{1,5}(/[0-9]{1,4}){0,2})(?(\\+(<)?(?[0-9]{1,5}(/[0-9]{1,4}){0,2}))"); - - private final @Nullable String dpt; - private final GroupAddress mainGA; - private final Set listenGAs; - private final Set readGAs; - - private GroupAddressConfiguration(@Nullable String dpt, GroupAddress mainGA, Set listenGAs, - Set readGAs) { - this.dpt = dpt; - this.mainGA = mainGA; - this.listenGAs = listenGAs; - this.readGAs = readGAs; - } - - public @Nullable String getDPT() { - return dpt; - } - - public GroupAddress getMainGA() { - return mainGA; - } - - public Set getListenGAs() { - return listenGAs; - } - - public Set getReadGAs() { - return readGAs; - } - - public static @Nullable GroupAddressConfiguration parse(@Nullable Object configuration) { - if (!(configuration instanceof String)) { - return null; - } - - Matcher matcher = PATTERN_GA_CONFIGURATION.matcher(((String) configuration).replace(" ", "")); - if (matcher.matches()) { - // Listen GAs - String input = matcher.group("listenGAs"); - Matcher m2 = PATTERN_LISTEN_GA.matcher(input); - Set listenGAs = new HashSet<>(); - Set readGAs = new HashSet<>(); - while (m2.find()) { - String ga = m2.group("GA"); - try { - GroupAddress groupAddress = new GroupAddress(ga); - listenGAs.add(groupAddress); - if (m2.group("read") != null) { - readGAs.add(groupAddress); - } - } catch (KNXFormatException e) { - LOGGER.warn("Failed to create GroupAddress from {}", ga); - return null; - } - } - - // Main GA - String mainGA = matcher.group("mainGA"); - try { - GroupAddress groupAddress = new GroupAddress(mainGA); - listenGAs.add(groupAddress); // also listening to main GA - if (matcher.group("read") != null) { - readGAs.add(groupAddress); // also reading main GA - } - return new GroupAddressConfiguration(matcher.group("dpt"), groupAddress, listenGAs, readGAs); - } catch (KNXFormatException e) { - LOGGER.warn("Failed to create GroupAddress from {}", mainGA); - return null; - } - - } else { - LOGGER.warn("Failed parsing channel configuration '{}'.", configuration); - } - - return null; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannel.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannel.java deleted file mode 100644 index 05177659d4..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannel.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static java.util.stream.Collectors.*; -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.CONTROL_CHANNEL_TYPES; -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.GA; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.config.core.Configuration; -import org.openhab.core.thing.Channel; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.types.Type; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.binding.knx.internal.client.InboundSpec; -import org.smarthomej.binding.knx.internal.client.OutboundSpec; -import org.smarthomej.binding.knx.internal.dpt.DPTUtil; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Meta-data abstraction for the KNX channel configurations. - * - * @author Simon Kaufmann - initial contribution and API - * @author Jan N. Klug - refactored from type definition to channel instance - * - */ -@NonNullByDefault -public abstract class KNXChannel { - private final Logger logger = LoggerFactory.getLogger(KNXChannel.class); - private final Set gaKeys; - private final Map groupAddressConfigurations = new HashMap<>(); - private final Set listenAddresses = new HashSet<>(); - private final Set writeAddresses = new HashSet<>(); - private final String channelType; - private final ChannelUID channelUID; - private final boolean isControl; - private final Class preferredType; - - KNXChannel(List> acceptedTypes, Channel channel) { - this(Set.of(GA), acceptedTypes, channel); - } - - KNXChannel(Set gaKeys, List> acceptedTypes, Channel channel) { - this.gaKeys = gaKeys; - this.preferredType = acceptedTypes.get(0); - - // this is safe because we already checked the presence of the ChannelTypeUID before - this.channelType = Objects.requireNonNull(channel.getChannelTypeUID()).getId(); - this.channelUID = channel.getUID(); - this.isControl = CONTROL_CHANNEL_TYPES.contains(channelType); - - // build map of ChannelConfigurations and GA lists - Configuration configuration = channel.getConfiguration(); - gaKeys.forEach(key -> { - GroupAddressConfiguration groupAddressConfiguration = GroupAddressConfiguration - .parse(configuration.get(key)); - if (groupAddressConfiguration != null) { - // check DPT configuration (if set) is compatible with item - String dpt = groupAddressConfiguration.getDPT(); - if (dpt != null) { - Set> types = DPTUtil.getAllowedTypes(dpt); - if (acceptedTypes.stream().noneMatch(types::contains)) { - logger.warn("Configured DPT '{}' is incompatible with accepted types '{}' for channel '{}'", - dpt, acceptedTypes, channelUID); - } - } - groupAddressConfigurations.put(key, groupAddressConfiguration); - // store address configuration for re-use - listenAddresses.addAll(groupAddressConfiguration.getListenGAs()); - writeAddresses.add(groupAddressConfiguration.getMainGA()); - } - }); - } - - public String getChannelType() { - return channelType; - } - - public ChannelUID getChannelUID() { - return channelUID; - } - - public boolean isControl() { - return isControl; - } - - public Class preferredType() { - return preferredType; - } - - public final Set getAllGroupAddresses() { - return listenAddresses; - } - - public final Set getWriteAddresses() { - return writeAddresses; - } - - public final @Nullable OutboundSpec getCommandSpec(Type command) { - logger.trace("getCommandSpec checking keys '{}' for command '{}' ({})", gaKeys, command, command.getClass()); - for (Map.Entry entry : groupAddressConfigurations.entrySet()) { - String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey())); - Set> expectedTypeClass = DPTUtil.getAllowedTypes(dpt); - if (expectedTypeClass.contains(command.getClass())) { - logger.trace("getCommandSpec key '{}' has expectedTypeClass '{}', matching command '{}' and dpt '{}'", - entry.getKey(), expectedTypeClass, command, dpt); - return new WriteSpecImpl(entry.getValue(), dpt, command); - } - } - logger.trace("getCommandSpec no Spec found!"); - return null; - } - - public final List getReadSpec() { - return groupAddressConfigurations.entrySet().stream() - .map(entry -> new ReadRequestSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey()))) - .filter(spec -> !spec.getGroupAddresses().isEmpty()).collect(toList()); - } - - public final @Nullable InboundSpec getListenSpec(GroupAddress groupAddress) { - return groupAddressConfigurations.entrySet().stream() - .map(entry -> new ListenSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey()))) - .filter(spec -> spec.getGroupAddresses().contains(groupAddress)).findFirst().orElse(null); - } - - public final @Nullable OutboundSpec getResponseSpec(GroupAddress groupAddress, Type value) { - return groupAddressConfigurations.entrySet().stream() - .map(entry -> new ReadResponseSpecImpl(entry.getValue(), getDefaultDPT(entry.getKey()), value)) - .filter(spec -> spec.matchesDestination(groupAddress)).findFirst().orElse(null); - } - - protected abstract String getDefaultDPT(String gaConfigKey); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannelFactory.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannelFactory.java deleted file mode 100644 index 1b9fed330d..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/KNXChannelFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.Map; -import java.util.Set; -import java.util.function.Function; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.Channel; -import org.openhab.core.thing.type.ChannelTypeUID; - -/** - * Helper class to find the matching {@link KNXChannel} for any given {@link ChannelTypeUID}. - * - * @author Simon Kaufmann - initial contribution and API - * @author Jan N. Klug - refactored ro factory class - * - */ -@NonNullByDefault -public final class KNXChannelFactory { - - private static final Map, Function> TYPES = Map.ofEntries( // - Map.entry(TypeColor.SUPPORTED_CHANNEL_TYPES, TypeColor::new), // - Map.entry(TypeContact.SUPPORTED_CHANNEL_TYPES, TypeContact::new), // - Map.entry(TypeDateTime.SUPPORTED_CHANNEL_TYPES, TypeDateTime::new), // - Map.entry(TypeDimmer.SUPPORTED_CHANNEL_TYPES, TypeDimmer::new), // - Map.entry(TypeNumber.SUPPORTED_CHANNEL_TYPES, TypeNumber::new), // - Map.entry(TypeRollershutter.SUPPORTED_CHANNEL_TYPES, TypeRollershutter::new), // - Map.entry(TypeString.SUPPORTED_CHANNEL_TYPES, TypeString::new), // - Map.entry(TypeSwitch.SUPPORTED_CHANNEL_TYPES, TypeSwitch::new)); - - private KNXChannelFactory() { - // prevent instantiation - } - - public static KNXChannel createKnxChannel(Channel channel) throws IllegalArgumentException { - ChannelTypeUID channelTypeUID = channel.getChannelTypeUID(); - if (channelTypeUID == null) { - throw new IllegalArgumentException("Could not determine ChannelTypeUID for channel " + channel.getUID()); - } - - String channelType = channelTypeUID.getId(); - - Function supplier = TYPES.entrySet().stream().filter(e -> e.getKey().contains(channelType)) - .map(Map.Entry::getValue).findFirst() - .orElseThrow(() -> new IllegalArgumentException(channelTypeUID + " is not a valid channel type ID")); - - return supplier.apply(channel); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ListenSpecImpl.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ListenSpecImpl.java deleted file mode 100644 index f04326a58b..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ListenSpecImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.smarthomej.binding.knx.internal.client.InboundSpec; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Listen meta-data. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class ListenSpecImpl implements InboundSpec { - private final String dpt; - private final Set listenAddresses; - - public ListenSpecImpl(GroupAddressConfiguration groupAddressConfiguration, String defaultDPT) { - this.dpt = Objects.requireNonNullElse(groupAddressConfiguration.getDPT(), defaultDPT); - this.listenAddresses = groupAddressConfiguration.getListenGAs(); - } - - @Override - public String getDPT() { - return dpt; - } - - @Override - public Set getGroupAddresses() { - return listenAddresses; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadRequestSpecImpl.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadRequestSpecImpl.java deleted file mode 100644 index 9b14e0b20e..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadRequestSpecImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.smarthomej.binding.knx.internal.client.InboundSpec; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Read meta-data. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class ReadRequestSpecImpl implements InboundSpec { - private final String dpt; - private final Set readAddresses; - - public ReadRequestSpecImpl(GroupAddressConfiguration groupAddressConfiguration, String defaultDPT) { - this.dpt = Objects.requireNonNullElse(groupAddressConfiguration.getDPT(), defaultDPT); - this.readAddresses = groupAddressConfiguration.getReadGAs(); - } - - @Override - public String getDPT() { - return dpt; - } - - @Override - public Set getGroupAddresses() { - return readAddresses; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadResponseSpecImpl.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadResponseSpecImpl.java deleted file mode 100644 index f4602300cc..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/ReadResponseSpecImpl.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.Objects; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.types.Type; -import org.smarthomej.binding.knx.internal.client.OutboundSpec; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Response meta-data - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class ReadResponseSpecImpl implements OutboundSpec { - private final String dpt; - private final GroupAddress groupAddress; - private final Type value; - - public ReadResponseSpecImpl(GroupAddressConfiguration groupAddressConfiguration, String defaultDPT, Type state) { - this.dpt = Objects.requireNonNullElse(groupAddressConfiguration.getDPT(), defaultDPT); - this.groupAddress = groupAddressConfiguration.getMainGA(); - this.value = state; - } - - @Override - public String getDPT() { - return dpt; - } - - @Override - public GroupAddress getGroupAddress() { - return groupAddress; - } - - @Override - public Type getValue() { - return value; - } - - @Override - public boolean matchesDestination(GroupAddress groupAddress) { - return groupAddress.equals(this.groupAddress); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeColor.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeColor.java deleted file mode 100644 index d5bf6b70e5..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeColor.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; -import tuwien.auto.calimero.dptxlator.DPTXlatorRGB; - -/** - * color channel type description - * - * @author Helmut Lehmeyer - initial contribution - * - */ -@NonNullByDefault -class TypeColor extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_COLOR, CHANNEL_COLOR_CONTROL); - - TypeColor(Channel channel) { - super(Set.of(SWITCH_GA, POSITION_GA, INCREASE_DECREASE_GA, HSB_GA), - List.of(HSBType.class, PercentType.class, OnOffType.class, IncreaseDecreaseType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - if (gaConfigKey.equals(HSB_GA)) { - return DPTXlatorRGB.DPT_RGB.getID(); - } - if (gaConfigKey.equals(INCREASE_DECREASE_GA)) { - return DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID(); - } - if (gaConfigKey.equals(SWITCH_GA)) { - return DPTXlatorBoolean.DPT_SWITCH.getID(); - } - if (gaConfigKey.equals(POSITION_GA)) { - return DPTXlator8BitUnsigned.DPT_SCALING.getID(); - } - throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported"); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeContact.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeContact.java deleted file mode 100644 index c44c7341e6..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeContact.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; - -/** - * contact channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeContact extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_CONTACT, CHANNEL_CONTACT_CONTROL); - - TypeContact(Channel channel) { - super(List.of(OpenClosedType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return DPTXlatorBoolean.DPT_OPENCLOSE.getID(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDateTime.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDateTime.java deleted file mode 100644 index 31b68ff91d..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDateTime.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlatorDateTime; - -/** - * datetime channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeDateTime extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_DATETIME, CHANNEL_DATETIME_CONTROL); - - TypeDateTime(Channel channel) { - super(List.of(DateTimeType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return DPTXlatorDateTime.DPT_DATE_TIME.getID(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDimmer.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDimmer.java deleted file mode 100644 index 1f8811dbad..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeDimmer.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; - -/** - * dimmer channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeDimmer extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_DIMMER, CHANNEL_DIMMER_CONTROL); - - TypeDimmer(Channel channel) { - super(Set.of(SWITCH_GA, POSITION_GA, INCREASE_DECREASE_GA), - List.of(PercentType.class, OnOffType.class, IncreaseDecreaseType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - if (Objects.equals(gaConfigKey, INCREASE_DECREASE_GA)) { - return DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID(); - } - if (Objects.equals(gaConfigKey, SWITCH_GA)) { - return DPTXlatorBoolean.DPT_SWITCH.getID(); - } - if (Objects.equals(gaConfigKey, POSITION_GA)) { - return DPTXlator8BitUnsigned.DPT_SCALING.getID(); - } - throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported"); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeNumber.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeNumber.java deleted file mode 100644 index 403348bbc0..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeNumber.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.thing.Channel; - -/** - * number channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeNumber extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_NUMBER, CHANNEL_NUMBER_CONTROL); - - TypeNumber(Channel channel) { - super(List.of(DecimalType.class, QuantityType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return "9.001"; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeRollershutter.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeRollershutter.java deleted file mode 100644 index 2e64758c99..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeRollershutter.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.library.types.StopMoveType; -import org.openhab.core.library.types.UpDownType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlator8BitUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; - -/** - * rollershutter channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeRollershutter extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_ROLLERSHUTTER, - CHANNEL_ROLLERSHUTTER_CONTROL); - - TypeRollershutter(Channel channel) { - super(Set.of(UP_DOWN_GA, STOP_MOVE_GA, POSITION_GA), - List.of(PercentType.class, UpDownType.class, StopMoveType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - if (Objects.equals(gaConfigKey, UP_DOWN_GA)) { - return DPTXlatorBoolean.DPT_UPDOWN.getID(); - } - if (Objects.equals(gaConfigKey, STOP_MOVE_GA)) { - return DPTXlatorBoolean.DPT_START.getID(); - } - if (Objects.equals(gaConfigKey, POSITION_GA)) { - return DPTXlator8BitUnsigned.DPT_SCALING.getID(); - } - throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported"); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeString.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeString.java deleted file mode 100644 index 93be7729bf..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeString.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.StringType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlatorString; - -/** - * string channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeString extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_STRING, CHANNEL_STRING_CONTROL); - - TypeString(Channel channel) { - super(List.of(StringType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return DPTXlatorString.DPT_STRING_8859_1.getID(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeSwitch.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeSwitch.java deleted file mode 100644 index 033b974043..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/TypeSwitch.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.thing.Channel; - -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; - -/** - * switch channel type description - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -class TypeSwitch extends KNXChannel { - public static final Set SUPPORTED_CHANNEL_TYPES = Set.of(CHANNEL_SWITCH, CHANNEL_SWITCH_CONTROL); - - TypeSwitch(Channel channel) { - super(List.of(OnOffType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return DPTXlatorBoolean.DPT_SWITCH.getID(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/WriteSpecImpl.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/WriteSpecImpl.java deleted file mode 100644 index 939439637f..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/channel/WriteSpecImpl.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import java.util.Objects; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.types.Type; -import org.smarthomej.binding.knx.internal.client.OutboundSpec; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Command meta-data - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class WriteSpecImpl implements OutboundSpec { - private final String dpt; - private final Type value; - private final GroupAddress groupAddress; - - public WriteSpecImpl(GroupAddressConfiguration groupAddressConfiguration, String defaultDPT, Type value) { - this.dpt = Objects.requireNonNullElse(groupAddressConfiguration.getDPT(), defaultDPT); - this.groupAddress = groupAddressConfiguration.getMainGA(); - this.value = value; - } - - @Override - public String getDPT() { - return dpt; - } - - @Override - public Type getValue() { - return value; - } - - @Override - public GroupAddress getGroupAddress() { - return groupAddress; - } - - @Override - public boolean matchesDestination(GroupAddress groupAddress) { - return groupAddress.equals(this.groupAddress); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/AbstractKNXClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/AbstractKNXClient.java deleted file mode 100644 index f53801f1f0..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/AbstractKNXClient.java +++ /dev/null @@ -1,453 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import static org.smarthomej.binding.knx.internal.dpt.DPTUtil.NORMALIZED_DPT; - -import java.time.Duration; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.openhab.core.thing.ThingUID; -import org.openhab.core.types.Type; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.binding.knx.internal.dpt.ValueEncoder; -import org.smarthomej.binding.knx.internal.handler.GroupAddressListener; - -import tuwien.auto.calimero.CloseEvent; -import tuwien.auto.calimero.DetachEvent; -import tuwien.auto.calimero.FrameEvent; -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.datapoint.CommandDP; -import tuwien.auto.calimero.datapoint.Datapoint; -import tuwien.auto.calimero.device.ProcessCommunicationResponder; -import tuwien.auto.calimero.link.KNXNetworkLink; -import tuwien.auto.calimero.link.NetworkLinkListener; -import tuwien.auto.calimero.mgmt.Destination; -import tuwien.auto.calimero.mgmt.ManagementClient; -import tuwien.auto.calimero.mgmt.ManagementClientImpl; -import tuwien.auto.calimero.mgmt.ManagementProcedures; -import tuwien.auto.calimero.mgmt.ManagementProceduresImpl; -import tuwien.auto.calimero.process.ProcessCommunication; -import tuwien.auto.calimero.process.ProcessCommunicator; -import tuwien.auto.calimero.process.ProcessCommunicatorImpl; -import tuwien.auto.calimero.process.ProcessEvent; -import tuwien.auto.calimero.process.ProcessListener; -import tuwien.auto.calimero.secure.SecureApplicationLayer; -import tuwien.auto.calimero.secure.Security; - -/** - * KNX Client which encapsulates the communication with the KNX bus via the calimero libary. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public abstract class AbstractKNXClient implements NetworkLinkListener, KNXClient { - - private static final int MAX_SEND_ATTEMPTS = 2; - - private final Logger logger = LoggerFactory.getLogger(AbstractKNXClient.class); - - private final ThingUID thingUID; - private final int responseTimeout; - private final int readingPause; - private final int autoReconnectPeriod; - private final int readRetriesLimit; - private final StatusUpdateCallback statusUpdateCallback; - private final ScheduledExecutorService knxScheduler; - - private @Nullable ProcessCommunicator processCommunicator; - private @Nullable ProcessCommunicationResponder responseCommunicator; - private @Nullable ManagementProcedures managementProcedures; - private @Nullable ManagementClient managementClient; - private @Nullable KNXNetworkLink link; - private @Nullable DeviceInfoClient deviceInfoClient; - private @Nullable ScheduledFuture busJob; - private @Nullable ScheduledFuture connectJob; - - private final Set groupAddressListeners = new CopyOnWriteArraySet<>(); - private final LinkedBlockingQueue readDatapoints = new LinkedBlockingQueue<>(); - - @FunctionalInterface - private interface ListenerNotification { - void apply(BusMessageListener listener, IndividualAddress source, GroupAddress destination, byte[] asdu); - } - - @NonNullByDefault({}) - private final ProcessListener processListener = new ProcessListener() { - - @Override - public void detached(DetachEvent e) { - logger.debug("The KNX network link was detached from the process communicator"); - } - - @Override - public void groupWrite(ProcessEvent e) { - processEvent("Group Write", e, (listener, source, destination, asdu) -> listener - .onGroupWrite(AbstractKNXClient.this, source, destination, asdu)); - } - - @Override - public void groupReadRequest(ProcessEvent e) { - processEvent("Group Read Request", e, (listener, source, destination, asdu) -> listener - .onGroupRead(AbstractKNXClient.this, source, destination, asdu)); - } - - @Override - public void groupReadResponse(ProcessEvent e) { - processEvent("Group Read Response", e, (listener, source, destination, asdu) -> listener - .onGroupReadResponse(AbstractKNXClient.this, source, destination, asdu)); - } - }; - - public AbstractKNXClient(int autoReconnectPeriod, ThingUID thingUID, int responseTimeout, int readingPause, - int readRetriesLimit, ScheduledExecutorService knxScheduler, StatusUpdateCallback statusUpdateCallback) { - this.autoReconnectPeriod = autoReconnectPeriod; - this.thingUID = thingUID; - this.responseTimeout = responseTimeout; - this.readingPause = readingPause; - this.readRetriesLimit = readRetriesLimit; - this.knxScheduler = knxScheduler; - this.statusUpdateCallback = statusUpdateCallback; - } - - public void initialize() { - connect(); - } - - private void scheduleReconnectJob() { - if (autoReconnectPeriod > 0) { - connectJob = knxScheduler.schedule(this::connect, autoReconnectPeriod, TimeUnit.SECONDS); - } - } - - private void cancelReconnectJob() { - ScheduledFuture currentReconnectJob = connectJob; - if (currentReconnectJob != null) { - currentReconnectJob.cancel(true); - connectJob = null; - } - } - - protected abstract KNXNetworkLink establishConnection() throws KNXException, InterruptedException; - - private synchronized boolean connectIfNotAutomatic() { - if (!isConnected()) { - return connectJob == null && connect(); - } - return true; - } - - private synchronized boolean connect() { - if (isConnected()) { - return true; - } - try { - releaseConnection(); - - logger.debug("Bridge {} is connecting to the KNX bus", thingUID); - - KNXNetworkLink link = establishConnection(); - this.link = link; - - managementProcedures = new ManagementProceduresImpl(link); - - ManagementClient managementClient = new ManagementClientImpl(link); - managementClient.responseTimeout(Duration.ofSeconds(responseTimeout)); - this.managementClient = managementClient; - - deviceInfoClient = new DeviceInfoClientImpl(managementClient); - - ProcessCommunicator processCommunicator = new ProcessCommunicatorImpl(link); - processCommunicator.responseTimeout(Duration.ofSeconds(responseTimeout)); - processCommunicator.addProcessListener(processListener); - this.processCommunicator = processCommunicator; - - this.responseCommunicator = new ProcessCommunicationResponder(link, - new SecureApplicationLayer(link, Security.defaultInstallation())); - - link.addLinkListener(this); - - busJob = knxScheduler.scheduleWithFixedDelay(this::readNextQueuedDatapoint, 0, readingPause, - TimeUnit.MILLISECONDS); - - statusUpdateCallback.updateStatus(ThingStatus.ONLINE); - connectJob = null; - return true; - } catch (KNXException | InterruptedException e) { - logger.debug("Error connecting to the bus: {}", e.getMessage(), e); - disconnect(e); - scheduleReconnectJob(); - return false; - } - } - - private void disconnect(@Nullable Exception e) { - releaseConnection(); - if (e != null) { - String message = e.getLocalizedMessage(); - statusUpdateCallback.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, - message != null ? message : ""); - } else { - statusUpdateCallback.updateStatus(ThingStatus.OFFLINE); - } - } - - private void releaseConnection() { - logger.debug("Bridge {} is disconnecting from the KNX bus", thingUID); - readDatapoints.clear(); - busJob = nullify(busJob, j -> j.cancel(true)); - deviceInfoClient = null; - managementProcedures = nullify(managementProcedures, ManagementProcedures::detach); - managementClient = nullify(managementClient, ManagementClient::detach); - link = nullify(link, KNXNetworkLink::close); - processCommunicator = nullify(processCommunicator, pc -> { - pc.removeProcessListener(processListener); - pc.detach(); - }); - responseCommunicator = nullify(responseCommunicator, rc -> { - rc.removeProcessListener(processListener); - rc.detach(); - }); - } - - private @Nullable T nullify(@Nullable T target, @Nullable Consumer lastWill) { - if (target != null && lastWill != null) { - lastWill.accept(target); - } - return null; - } - - private void processEvent(String task, ProcessEvent event, ListenerNotification action) { - GroupAddress destination = event.getDestination(); - IndividualAddress source = event.getSourceAddr(); - byte[] asdu = event.getASDU(); - logger.trace("Received a {} telegram from '{}' to '{}' with value '{}'", task, source, destination, asdu); - for (GroupAddressListener listener : groupAddressListeners) { - if (listener.listensTo(destination)) { - knxScheduler.schedule(() -> action.apply(listener, source, destination, asdu), 0, TimeUnit.SECONDS); - } - } - } - - private void readNextQueuedDatapoint() { - if (!connectIfNotAutomatic()) { - return; - } - ProcessCommunicator processCommunicator = this.processCommunicator; - if (processCommunicator == null) { - return; - } - ReadDatapoint datapoint = readDatapoints.poll(); - if (datapoint != null) { - datapoint.incrementRetries(); - try { - logger.trace("Sending a Group Read Request telegram for {}", datapoint.getDatapoint().getMainAddress()); - processCommunicator.read(datapoint.getDatapoint()); - } catch (KNXException e) { - if (datapoint.getRetries() < datapoint.getLimit()) { - readDatapoints.add(datapoint); - logger.debug("Could not read value for datapoint {}: {}. Going to retry.", - datapoint.getDatapoint().getMainAddress(), e.getMessage()); - } else { - logger.warn("Giving up reading datapoint {}, the number of maximum retries ({}) is reached.", - datapoint.getDatapoint().getMainAddress(), datapoint.getLimit()); - } - } catch (InterruptedException e) { - logger.debug("Interrupted sending KNX read request"); - } - } - } - - public void dispose() { - cancelReconnectJob(); - disconnect(null); - } - - @Override - public void linkClosed(@Nullable CloseEvent closeEvent) { - KNXNetworkLink link = this.link; - if (link == null || closeEvent == null) { - return; - } - if (!link.isOpen() && CloseEvent.USER_REQUEST != closeEvent.getInitiator()) { - statusUpdateCallback.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, - closeEvent.getReason()); - logger.debug("KNX link has been lost (reason: {} on object {})", closeEvent.getReason(), - closeEvent.getSource().toString()); - scheduleReconnectJob(); - } - } - - @Override - public void indication(@Nullable FrameEvent e) { - // no-op - } - - @Override - public void confirmation(@Nullable FrameEvent e) { - // no-op - } - - @Override - public final synchronized boolean isReachable(@Nullable IndividualAddress address) throws KNXException { - ManagementProcedures managementProcedures = this.managementProcedures; - if (managementProcedures == null || address == null) { - return false; - } - try { - return managementProcedures.isAddressOccupied(address); - } catch (InterruptedException e) { - logger.debug("Interrupted pinging KNX device '{}'", address); - } - return false; - } - - @Override - public final synchronized void restartNetworkDevice(@Nullable IndividualAddress address) { - ManagementClient managementClient = this.managementClient; - if (address == null || managementClient == null) { - return; - } - Destination destination = null; - try { - destination = managementClient.createDestination(address, true); - managementClient.restart(destination); - } catch (KNXException e) { - logger.warn("Could not reset device with address '{}': {}", address, e.getMessage()); - } catch (InterruptedException e) { // ignored as in Calimero pre-2.4.0 - } finally { - if (destination != null) { - destination.destroy(); - } - } - } - - @Override - public void readDatapoint(Datapoint datapoint) { - synchronized (this) { - ReadDatapoint retryDatapoint = new ReadDatapoint(datapoint, readRetriesLimit); - if (!readDatapoints.contains(retryDatapoint)) { - readDatapoints.add(retryDatapoint); - } - } - } - - @Override - public final void registerGroupAddressListener(GroupAddressListener listener) { - groupAddressListeners.add(listener); - } - - @Override - public final void unregisterGroupAddressListener(GroupAddressListener listener) { - groupAddressListeners.remove(listener); - } - - @Override - public boolean isConnected() { - final KNXNetworkLink localLink = link; - return localLink != null && localLink.isOpen(); - } - - @Override - public DeviceInfoClient getDeviceInfoClient() { - DeviceInfoClient deviceInfoClient = this.deviceInfoClient; - if (deviceInfoClient != null) { - return deviceInfoClient; - } else { - throw new IllegalStateException(); - } - } - - @Override - public void writeToKNX(OutboundSpec commandSpec) throws KNXException { - ProcessCommunicator processCommunicator = this.processCommunicator; - KNXNetworkLink link = this.link; - if (processCommunicator == null || link == null) { - logger.debug("Cannot write to the KNX bus (processCommunicator: {}, link: {})", - processCommunicator == null ? "Not OK" : "OK", - link == null ? "Not OK" : (link.isOpen() ? "Open" : "Closed")); - return; - } - GroupAddress groupAddress = commandSpec.getGroupAddress(); - - logger.trace("writeToKNX groupAddress '{}', commandSpec '{}'", groupAddress, commandSpec); - - sendToKNX(processCommunicator, groupAddress, commandSpec.getDPT(), commandSpec.getValue()); - } - - @Override - public void respondToKNX(OutboundSpec responseSpec) throws KNXException { - ProcessCommunicationResponder responseCommunicator = this.responseCommunicator; - KNXNetworkLink link = this.link; - if (responseCommunicator == null || link == null) { - logger.debug("Cannot write to the KNX bus (responseCommunicator: {}, link: {})", - responseCommunicator == null ? "Not OK" : "OK", - link == null ? "Not OK" : (link.isOpen() ? "Open" : "Closed")); - return; - } - GroupAddress groupAddress = responseSpec.getGroupAddress(); - - logger.trace("respondToKNX groupAddress '{}', responseSpec '{}'", groupAddress, responseSpec); - - sendToKNX(responseCommunicator, groupAddress, responseSpec.getDPT(), responseSpec.getValue()); - } - - private void sendToKNX(ProcessCommunication communicator, GroupAddress groupAddress, String dpt, Type type) - throws KNXException { - if (!connectIfNotAutomatic()) { - return; - } - - Datapoint datapoint = new CommandDP(groupAddress, thingUID.toString(), 0, - NORMALIZED_DPT.getOrDefault(dpt, dpt)); - String mappedValue = ValueEncoder.encode(type, dpt); - if (mappedValue == null) { - logger.debug("Value '{}' of type '{}' cannot be mapped to datapoint '{}'", type, type.getClass(), - datapoint); - return; - } - logger.trace("sendToKNX mappedValue: '{}' groupAddress: '{}'", mappedValue, groupAddress); - - for (int i = 0;; i++) { - try { - communicator.write(datapoint, mappedValue); - logger.debug("Wrote value '{}' to datapoint '{}' ({}. attempt).", type, datapoint, i); - break; - } catch (KNXException e) { - if (i < MAX_SEND_ATTEMPTS - 1) { - logger.debug("Value '{}' could not be sent to the KNX bus using datapoint '{}': {}. Will retry.", - type, datapoint, e.getLocalizedMessage()); - } else { - logger.warn("Value '{}' could not be sent to the KNX bus using datapoint '{}': {}. Giving up now.", - type, datapoint, e.getLocalizedMessage()); - throw e; - } - } - } - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/BusMessageListener.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/BusMessageListener.java deleted file mode 100644 index 9bdf5b4764..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/BusMessageListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.IndividualAddress; - -/** - * Callback interface for KNX bus messages - * - * @author Simon Kaufmann - Initial contribution and API - */ -@NonNullByDefault -public interface BusMessageListener { - - /** - * Called when the KNX bridge receives a group write telegram - * - * @param client - * @param source - * @param destination - * @param asdu - */ - void onGroupWrite(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, byte[] asdu); - - /** - * Called when the KNX bridge receives a group read telegram - * - * @param client - * @param source - * @param destination - * @param asdu - */ - void onGroupRead(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, byte[] asdu); - - /** - * Called when the KNX bridge receives a group read response telegram - * - * @param client - * @param source - * @param destination - * @param asdu - */ - void onGroupReadResponse(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, byte[] asdu); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/CustomKNXNetworkLinkIP.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/CustomKNXNetworkLinkIP.java deleted file mode 100644 index bc74f237c0..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/CustomKNXNetworkLinkIP.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.knxnetip.KNXnetIPConnection; -import tuwien.auto.calimero.link.KNXNetworkLinkIP; -import tuwien.auto.calimero.link.medium.KNXMediumSettings; - -/** - * Subclass of {@link KNXNetworkLinkIP} which exposes the protected constructor in order to work-around - * https://github.com/calimero-project/calimero-core/issues/57 - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public class CustomKNXNetworkLinkIP extends KNXNetworkLinkIP { - - public static final int TUNNELING = KNXNetworkLinkIP.TUNNELING; - public static final int ROUTING = KNXNetworkLinkIP.ROUTING; - - CustomKNXNetworkLinkIP(final int serviceMode, KNXnetIPConnection conn, KNXMediumSettings settings) - throws KNXException, InterruptedException { - super(serviceMode, conn, settings); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClient.java deleted file mode 100644 index d4fbdc92e2..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClient.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -import tuwien.auto.calimero.IndividualAddress; - -/** - * Client to retrieve further information about KNX devices. - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public interface DeviceInfoClient { - - byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType, boolean authenticate, - long timeout); - - byte @Nullable [] readDeviceMemory(IndividualAddress address, int startAddress, int bytes, boolean authenticate, - long timeout); - - byte @Nullable [] readDeviceProperties(IndividualAddress address, final int interfaceObjectIndex, - final int propertyId, final int start, final int elements, boolean authenticate, long timeout); - - boolean isConnected(); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClientImpl.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClientImpl.java deleted file mode 100644 index 8e193fe90d..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInfoClientImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import java.nio.ByteBuffer; -import java.text.MessageFormat; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.mgmt.Destination; -import tuwien.auto.calimero.mgmt.ManagementClient; - -/** - * Client for retrieving additional device descriptions. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class DeviceInfoClientImpl implements DeviceInfoClient { - private final Logger logger = LoggerFactory.getLogger(DeviceInfoClientImpl.class); - private final ManagementClient managementClient; - - DeviceInfoClientImpl(ManagementClient managementClient) { - this.managementClient = managementClient; - } - - @FunctionalInterface - private interface ReadFunction { - @Nullable - R apply(T t) throws KNXException, InterruptedException; - } - - private byte @Nullable [] readFromManagementClient(String task, long timeout, IndividualAddress address, - ReadFunction function) { - final long start = System.nanoTime(); - while ((System.nanoTime() - start) < TimeUnit.MILLISECONDS.toNanos(timeout)) { - Destination destination = null; - try { - logger.trace("Going to {} of {} ", task, address); - destination = managementClient.createDestination(address, true); - byte[] result = function.apply(destination); - logger.trace("Finished to {} of {}, result: {}", task, address, result == null ? null : result.length); - return result; - } catch (KNXException e) { - logger.debug("Could not {} of {}: {}", task, address, e.getMessage()); - } catch (InterruptedException e) { - logger.trace("Interrupted to {}", task); - return null; - } finally { - if (destination != null) { - destination.destroy(); - } - } - } - return null; - } - - private void authorize(boolean authenticate, Destination destination) throws KNXException, InterruptedException { - if (authenticate) { - managementClient.authorize(destination, (ByteBuffer.allocate(4)).put((byte) 0xFF).put((byte) 0xFF) - .put((byte) 0xFF).put((byte) 0xFF).array()); - } - } - - @Override - public synchronized byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType, - boolean authenticate, long timeout) { - String task = "read the device description"; - return readFromManagementClient(task, timeout, address, destination -> { - authorize(authenticate, destination); - return managementClient.readDeviceDesc(destination, descType); - }); - } - - @Override - public synchronized byte @Nullable [] readDeviceMemory(IndividualAddress address, int startAddress, int bytes, - boolean authenticate, long timeout) { - String task = MessageFormat.format("read {0} bytes at memory location {1}", bytes, startAddress); - return readFromManagementClient(task, timeout, address, destination -> { - authorize(authenticate, destination); - return managementClient.readMemory(destination, startAddress, bytes); - }); - } - - @Override - public synchronized byte @Nullable [] readDeviceProperties(IndividualAddress address, - final int interfaceObjectIndex, final int propertyId, final int start, final int elements, - boolean authenticate, long timeout) { - String task = MessageFormat.format("read device property {0} at index {1}", propertyId, interfaceObjectIndex); - return readFromManagementClient(task, timeout, address, destination -> { - authorize(authenticate, destination); - return managementClient.readProperty(destination, interfaceObjectIndex, propertyId, start, elements); - }); - } - - @Override - public boolean isConnected() { - return managementClient.isOpen(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInspector.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInspector.java deleted file mode 100644 index 580f007056..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/DeviceInspector.java +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; -import static org.smarthomej.binding.knx.internal.handler.DeviceConstants.*; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import tuwien.auto.calimero.DataUnitBuilder; -import tuwien.auto.calimero.DeviceDescriptor; -import tuwien.auto.calimero.DeviceDescriptor.DD0; -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.mgmt.PropertyAccess.PID; - -/** - * Client dedicated to read device specific information using the {@link DeviceInfoClient}. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class DeviceInspector { - private static final long OPERATION_TIMEOUT = 5000; - private static final long OPERATION_INTERVAL = 2000; - - private final Logger logger = LoggerFactory.getLogger(DeviceInspector.class); - private final DeviceInfoClient client; - private final IndividualAddress address; - - public static class Result { - private final Map properties; - private final Set groupAddresses; - - public Result(Map properties, Set groupAddresses) { - super(); - this.properties = properties; - this.groupAddresses = groupAddresses; - } - - public Map getProperties() { - return properties; - } - - public Set getGroupAddresses() { - return groupAddresses; - } - } - - public DeviceInspector(DeviceInfoClient client, IndividualAddress address) { - this.client = client; - this.address = address; - } - - private DeviceInfoClient getClient() { - return client; - } - - @Nullable - public Result readDeviceInfo() { - if (!getClient().isConnected()) { - return null; - } - - logger.debug("Fetching device information for address {}", address); - Map properties = new HashMap<>(); - properties.putAll(readDeviceDescription(address)); - properties.putAll(readDeviceProperties(address)); - return new Result(properties, Collections.emptySet()); - } - - private Map readDeviceProperties(IndividualAddress address) { - Map ret = new HashMap<>(); - try { - Thread.sleep(OPERATION_INTERVAL); - // check if there is a Device Object in the KNX device - byte[] elements = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.OBJECT_TYPE, 0, 1, false, - OPERATION_TIMEOUT); - if ((elements == null ? 0 : toUnsigned(elements)) == 1) { - Thread.sleep(OPERATION_INTERVAL); - String manufacturerId = MANUFACTURER_MAP - .getOrDefault(toUnsigned(getClient().readDeviceProperties(address, DEVICE_OBJECT, - PID.MANUFACTURER_ID, 1, 1, false, OPERATION_TIMEOUT)), "Unknown"); - Thread.sleep(OPERATION_INTERVAL); - String serialNo = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.SERIAL_NUMBER, 1, - 1, false, OPERATION_TIMEOUT), ""); - Thread.sleep(OPERATION_INTERVAL); - String hardwareType = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, HARDWARE_TYPE, 1, - 1, false, OPERATION_TIMEOUT), " "); - Thread.sleep(OPERATION_INTERVAL); - String firmwareRevision = Integer.toString(toUnsigned(getClient().readDeviceProperties(address, - DEVICE_OBJECT, PID.FIRMWARE_REVISION, 1, 1, false, OPERATION_TIMEOUT))); - - ret.put(MANUFACTURER_NAME, manufacturerId); - if (serialNo != null) { - ret.put(MANUFACTURER_SERIAL_NO, serialNo); - } - if (hardwareType != null) { - ret.put(MANUFACTURER_HARDWARE_TYPE, hardwareType); - } - ret.put(MANUFACTURER_FIRMWARE_REVISION, firmwareRevision); - logger.debug("Identified device {} as a {}, type {}, revision {}, serial number {}", address, - manufacturerId, hardwareType, firmwareRevision, serialNo); - } else { - logger.debug("The KNX device with address {} does not expose a Device Object", address); - } - } catch (InterruptedException e) { - logger.debug("Interrupted while fetching the device description for a device '{}' : {}", address, - e.getMessage()); - } - return ret; - } - - private @Nullable String toHex(byte @Nullable [] input, String separator) { - return input == null ? null : DataUnitBuilder.toHex(input, separator); - } - - private Map readDeviceDescription(IndividualAddress address) { - Map ret = new HashMap<>(); - byte[] data = getClient().readDeviceDescription(address, 0, false, OPERATION_TIMEOUT); - if (data != null) { - final DD0 dd = DeviceDescriptor.DD0.from(data); - - String type = FIRMWARE_MAP.get(dd.firmwareType()); - if (type != null) { - ret.put(FIRMWARE_TYPE, type); - } - String version = FIRMWARE_MAP.get(dd.firmwareVersion()); - if (version != null) { - ret.put(FIRMWARE_VERSION, version); - } - String subVersion = FIRMWARE_MAP.get(dd.firmwareSubcode()); - if (subVersion != null) { - ret.put(FIRMWARE_SUBVERSION, subVersion); - } - logger.debug("The device with address {} is of type {}, version {}, subversion {}", address, type, version, - subVersion); - } else { - logger.debug("The KNX device with address {} does not expose a Device Descriptor", address); - } - return ret; - } - - private int toUnsigned(final byte @Nullable [] data) { - if (data == null) { - return 0; - } - int value = data[0] & 0xff; - if (data.length == 1) { - return value; - } - value = value << 8 | data[1] & 0xff; - if (data.length == 2) { - return value; - } - value = value << 16 | data[2] & 0xff << 8 | data[3] & 0xff; - return value; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/IPClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/IPClient.java deleted file mode 100644 index 87459c09af..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/IPClient.java +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.concurrent.ScheduledExecutorService; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.thing.ThingUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.KNXIllegalArgumentException; -import tuwien.auto.calimero.knxnetip.KNXnetIPConnection; -import tuwien.auto.calimero.knxnetip.KNXnetIPRouting; -import tuwien.auto.calimero.knxnetip.KNXnetIPTunnel; -import tuwien.auto.calimero.knxnetip.KNXnetIPTunnel.TunnelingLayer; -import tuwien.auto.calimero.link.KNXNetworkLink; -import tuwien.auto.calimero.link.KNXNetworkLinkIP; -import tuwien.auto.calimero.link.medium.KNXMediumSettings; -import tuwien.auto.calimero.link.medium.TPSettings; - -/** - * IP specific {@link AbstractKNXClient} implementation. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class IPClient extends AbstractKNXClient { - - private final Logger logger = LoggerFactory.getLogger(IPClient.class); - - private static final String MODE_ROUTER = "ROUTER"; - private static final String MODE_TUNNEL = "TUNNEL"; - - private final int ipConnectionType; - private final String ip; - private final String localSource; - private final int port; - @Nullable - private final InetSocketAddress localEndPoint; - private final boolean useNAT; - - public IPClient(int ipConnectionType, String ip, String localSource, int port, - @Nullable InetSocketAddress localEndPoint, boolean useNAT, int autoReconnectPeriod, ThingUID thingUID, - int responseTimeout, int readingPause, int readRetriesLimit, ScheduledExecutorService knxScheduler, - StatusUpdateCallback statusUpdateCallback) { - super(autoReconnectPeriod, thingUID, responseTimeout, readingPause, readRetriesLimit, knxScheduler, - statusUpdateCallback); - this.ipConnectionType = ipConnectionType; - this.ip = ip; - this.localSource = localSource; - this.port = port; - this.localEndPoint = localEndPoint; - this.useNAT = useNAT; - } - - @Override - protected KNXNetworkLink establishConnection() throws KNXException, InterruptedException { - logger.debug("Establishing connection to KNX bus on {}:{} in mode {}.", ip, port, connectionTypeToString()); - TPSettings settings = new TPSettings(new IndividualAddress(localSource)); - return createKNXNetworkLinkIP(ipConnectionType, localEndPoint, new InetSocketAddress(ip, port), useNAT, - settings); - } - - private String connectionTypeToString() { - return ipConnectionType == CustomKNXNetworkLinkIP.ROUTING ? MODE_ROUTER : MODE_TUNNEL; - } - - private KNXNetworkLinkIP createKNXNetworkLinkIP(int serviceMode, @Nullable InetSocketAddress localEP, - @Nullable InetSocketAddress remoteEP, boolean useNAT, KNXMediumSettings settings) - throws KNXException, InterruptedException { - // creating the connection here as a workaround for - // https://github.com/calimero-project/calimero-core/issues/57 - KNXnetIPConnection conn = getConnection(serviceMode, localEP, remoteEP, useNAT); - return new CustomKNXNetworkLinkIP(serviceMode, conn, settings); - } - - private KNXnetIPConnection getConnection(int serviceMode, @Nullable InetSocketAddress localEP, - @Nullable InetSocketAddress remoteEP, boolean useNAT) throws KNXException, InterruptedException { - KNXnetIPConnection conn; - switch (serviceMode) { - case CustomKNXNetworkLinkIP.TUNNELING: - InetSocketAddress local = localEP; - if (local == null) { - try { - local = new InetSocketAddress(InetAddress.getLocalHost(), 0); - } catch (final UnknownHostException e) { - throw new KNXException("no local host available"); - } - } - conn = new KNXnetIPTunnel(TunnelingLayer.LinkLayer, local, remoteEP, useNAT); - break; - case CustomKNXNetworkLinkIP.ROUTING: - NetworkInterface netIf = null; - if (localEP != null && !localEP.isUnresolved()) { - try { - netIf = NetworkInterface.getByInetAddress(localEP.getAddress()); - } catch (final SocketException e) { - throw new KNXException("error getting network interface: " + e.getMessage()); - } - } - final InetAddress mcast = remoteEP != null ? remoteEP.getAddress() : null; - conn = new KNXnetIPRouting(netIf, mcast); - break; - default: - throw new KNXIllegalArgumentException("unknown service mode"); - } - return conn; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/InboundSpec.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/InboundSpec.java deleted file mode 100644 index ef107164bf..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/InboundSpec.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Describes the relevant parameters for reading from/listening to the KNX bus. - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public interface InboundSpec { - - /** - * Get the datapoint type. - * - * @return the datapoint type - */ - String getDPT(); - - /** - * Get the affected group addresses. - * - * @return a list of group addresses. - */ - Set getGroupAddresses(); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/KNXClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/KNXClient.java deleted file mode 100644 index f391429b29..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/KNXClient.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.smarthomej.binding.knx.internal.handler.GroupAddressListener; - -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.datapoint.Datapoint; - -/** - * Client for communicating with the KNX bus. - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public interface KNXClient { - - /** - * Check whether the client is connected - * - * @return {@code true} if the client currently is connected - */ - boolean isConnected(); - - /** - * Determines whether the supplied address is occupied by a device in the KNX network or not. - * - * @param address the individual address to check - * @return {@code true} if the address is occupied - * @throws KNXException on network or send errors - */ - boolean isReachable(@Nullable IndividualAddress address) throws KNXException; - - /** - * Get the {@link DeviceInfoClient} which allows further device inspection. - * - * @return the device infor client - * @throws IllegalStateException in case the client is not connected - */ - DeviceInfoClient getDeviceInfoClient(); - - /** - * Initiates a basic restart of the device with the given address. - * - * @param address the individual address of the device - */ - void restartNetworkDevice(@Nullable IndividualAddress address); - - /** - * Register the given listener to be informed on KNX bus traffic. - * - * @param listener the listener - */ - void registerGroupAddressListener(GroupAddressListener listener); - - /** - * Remove the given listener. - * - * @param listener the listener - */ - void unregisterGroupAddressListener(GroupAddressListener listener); - - /** - * Schedule the given data point for asynchronous reading. - * - * @param datapoint the datapoint - */ - void readDatapoint(Datapoint datapoint); - - /** - * Write a command to the KNX bus. - * - * @param commandSpec the outbound spec - * @throws KNXException if any problem with the communication arises. - */ - void writeToKNX(OutboundSpec commandSpec) throws KNXException; - - /** - * Send a state as a read-response to the KNX bus. - * - * @param responseSpec the outbound spec - * @throws KNXException if any problem with the communication arises. - */ - void respondToKNX(OutboundSpec responseSpec) throws KNXException; -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/NoOpClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/NoOpClient.java deleted file mode 100644 index a6b1843694..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/NoOpClient.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.smarthomej.binding.knx.internal.handler.GroupAddressListener; - -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.datapoint.Datapoint; - -/** - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public class NoOpClient implements KNXClient { - - @Override - public boolean isConnected() { - return false; - } - - @Override - public boolean isReachable(@Nullable IndividualAddress address) throws KNXException { - return false; - } - - @Override - public DeviceInfoClient getDeviceInfoClient() { - throw new IllegalStateException("KNX client not properly configured"); - } - - @Override - public void restartNetworkDevice(@Nullable IndividualAddress address) { - throw new IllegalStateException("KNX client not properly configured"); - } - - @Override - public void registerGroupAddressListener(GroupAddressListener listener) { - } - - @Override - public void unregisterGroupAddressListener(GroupAddressListener listener) { - } - - @Override - public void readDatapoint(Datapoint datapoint) { - } - - @Override - public void writeToKNX(OutboundSpec commandSpec) throws KNXException { - } - - @Override - public void respondToKNX(OutboundSpec responseSpec) throws KNXException { - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/OutboundSpec.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/OutboundSpec.java deleted file mode 100644 index 3dfb87eaa8..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/OutboundSpec.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.types.Type; - -import tuwien.auto.calimero.GroupAddress; - -/** - * Describes the relevant parameters for writing to the KNX bus. - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public interface OutboundSpec { - - /** - * Get the datapoint type. - * - * @return the datapoint type - */ - String getDPT(); - - /** - * The group address to be used. - * - * @return the group address - */ - GroupAddress getGroupAddress(); - - /** - * The command or state to be sent. - * - * @return the command/state - */ - Type getValue(); - - boolean matchesDestination(GroupAddress groupAddress); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/ReadDatapoint.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/ReadDatapoint.java deleted file mode 100644 index 5570e06636..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/ReadDatapoint.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -import tuwien.auto.calimero.datapoint.Datapoint; - -/** - * Information about a data point which is queued to be read from the KNX bus. - * - * @author Karel Goderis - Initial contribution - */ -@NonNullByDefault -public class ReadDatapoint { - - private final Datapoint datapoint; - private int retries; - private final int limit; - - public ReadDatapoint(Datapoint datapoint, int limit) { - this.datapoint = datapoint; - this.retries = 0; - this.limit = limit; - } - - public Datapoint getDatapoint() { - return datapoint; - } - - public int getRetries() { - return retries; - } - - public void incrementRetries() { - this.retries++; - } - - public int getLimit() { - return limit; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((datapoint.getMainAddress() == null) ? 0 : datapoint.getMainAddress().hashCode()); - return result; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ReadDatapoint other = (ReadDatapoint) obj; - - return datapoint.getMainAddress().equals(other.datapoint.getMainAddress()); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/SerialClient.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/SerialClient.java deleted file mode 100644 index 082dea659b..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/SerialClient.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import java.util.Enumeration; -import java.util.concurrent.ScheduledExecutorService; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.ThingUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import gnu.io.CommPortIdentifier; -import gnu.io.RXTXVersion; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.link.KNXNetworkLink; -import tuwien.auto.calimero.link.KNXNetworkLinkFT12; -import tuwien.auto.calimero.link.medium.KNXMediumSettings; -import tuwien.auto.calimero.link.medium.TPSettings; - -/** - * Serial specific {@link AbstractKNXClient} implementation. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class SerialClient extends AbstractKNXClient { - - private final Logger logger = LoggerFactory.getLogger(SerialClient.class); - - private final String serialPort; - private final boolean useCEMI; - - public SerialClient(int autoReconnectPeriod, ThingUID thingUID, int responseTimeout, int readingPause, - int readRetriesLimit, ScheduledExecutorService knxScheduler, String serialPort, boolean useCEMI, - StatusUpdateCallback statusUpdateCallback) { - super(autoReconnectPeriod, thingUID, responseTimeout, readingPause, readRetriesLimit, knxScheduler, - statusUpdateCallback); - this.serialPort = serialPort; - this.useCEMI = useCEMI; - } - - @Override - protected KNXNetworkLink establishConnection() throws KNXException, InterruptedException { - try { - RXTXVersion.getVersion(); - logger.debug("Establishing connection to KNX bus through FT1.2 on serial port {}.", serialPort); - KNXMediumSettings settings = new TPSettings(); - if (useCEMI) { - return KNXNetworkLinkFT12.newCemiLink(serialPort, settings); - } else { - return new KNXNetworkLinkFT12(serialPort, settings); - } - } catch (NoClassDefFoundError e) { - throw new KNXException( - "The serial FT1.2 KNX connection requires the RXTX libraries to be available, but they could not be found!", - e); - } catch (KNXException e) { - String message = e.getMessage(); - if (message != null && message.startsWith("can not open serial port")) { - StringBuilder sb = new StringBuilder("Available ports are:\n"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier id = (CommPortIdentifier) portList.nextElement(); - if (id != null && id.getPortType() == CommPortIdentifier.PORT_SERIAL) { - sb.append(id.getName()); - sb.append("\n"); - } - } - sb.deleteCharAt(sb.length() - 1); - throw new KNXException("Serial port '" + serialPort + "' could not be opened. " + sb); - } else { - throw e; - } - } - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/StatusUpdateCallback.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/StatusUpdateCallback.java deleted file mode 100644 index 1adc05b4cd..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/client/StatusUpdateCallback.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.client; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; - -/** - * Callback interface which enables the KNXClient implementations to update the thing status. - * - * @author Simon Kaufmann - Initial contribution - * - */ -@NonNullByDefault -public interface StatusUpdateCallback { - - /** - * Updates the status of the thing. - * - * see {@link org.openhab.core.thing.binding.BaseThingHandler} - * - * @param status the status - */ - void updateStatus(ThingStatus status); - - /** - * Updates the status of the thing. - * - * see {@link org.openhab.core.thing.binding.BaseThingHandler} - * - * @param status the status - * @param statusDetail the detail of the status - * @param description the description of the status - */ - void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, String description); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/BridgeConfiguration.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/BridgeConfiguration.java deleted file mode 100644 index 3d959106db..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/BridgeConfiguration.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * {@link org.smarthomej.binding.knx.internal.handler.KNXBridgeBaseThingHandler} configuration - * - * @author Simon Kaufmann - Initial contribution - * - */ -@NonNullByDefault -public class BridgeConfiguration { - private int autoReconnectPeriod; - private int readingPause = 50; - private int readRetriesLimit = 3; - private int responseTimeout = 10; - - public int getAutoReconnectPeriod() { - return autoReconnectPeriod; - } - - public int getReadingPause() { - return readingPause; - } - - public int getReadRetriesLimit() { - return readRetriesLimit; - } - - public int getResponseTimeout() { - return responseTimeout; - } - - public void setAutoReconnectPeriod(int period) { - autoReconnectPeriod = period; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/DeviceConfig.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/DeviceConfig.java deleted file mode 100644 index 2e56de633e..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/DeviceConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Configuration object for the device thing handler. - * - * @author Karel Goderis - Initial contribution - * @author Simon Kaufmann - refactoring & cleanup - */ -@NonNullByDefault -public class DeviceConfig { - private @Nullable String address; - private boolean fetch = false; - private int pingInterval = 600; - private int readInterval = 0; - - public @Nullable String getAddress() { - return address; - } - - public boolean getFetch() { - return fetch; - } - - public int getPingInterval() { - return pingInterval; - } - - public int getReadInterval() { - return readInterval; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/IPBridgeConfiguration.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/IPBridgeConfiguration.java deleted file mode 100644 index d21b8a0636..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/IPBridgeConfiguration.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * IP Bridge handler configuration object. - * - * @author Simon Kaufmann - initial contribution and API - * - */ -@NonNullByDefault -public class IPBridgeConfiguration extends BridgeConfiguration { - - private boolean useNAT = false; - private @Nullable String type; - private @Nullable String ipAddress; - private int portNumber = 3671; - private @Nullable String localIp; - private String localSourceAddr = "0.0.0"; - - public Boolean getUseNAT() { - return useNAT; - } - - public @Nullable String getType() { - return type; - } - - public @Nullable String getIpAddress() { - return ipAddress; - } - - public int getPortNumber() { - return portNumber; - } - - public @Nullable String getLocalIp() { - return localIp; - } - - public String getLocalSourceAddr() { - return localSourceAddr; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/SerialBridgeConfiguration.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/SerialBridgeConfiguration.java deleted file mode 100644 index 3731caf3df..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/config/SerialBridgeConfiguration.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * Serial Bridge configuration object. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@NonNullByDefault -public class SerialBridgeConfiguration extends BridgeConfiguration { - public @Nullable String serialPort; - public boolean useCEMI = false; -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUnits.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUnits.java deleted file mode 100644 index 16353dd1e2..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUnits.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.dpt; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.library.unit.SIUnits; -import org.openhab.core.library.unit.Units; - -import tuwien.auto.calimero.dptxlator.DPT; -import tuwien.auto.calimero.dptxlator.DPTXlator; -import tuwien.auto.calimero.dptxlator.DPTXlator2ByteFloat; -import tuwien.auto.calimero.dptxlator.DPTXlator2ByteUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlator4ByteFloat; -import tuwien.auto.calimero.dptxlator.DPTXlator4ByteSigned; -import tuwien.auto.calimero.dptxlator.DPTXlator4ByteUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlator64BitSigned; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitSigned; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitUnsigned; -import tuwien.auto.calimero.dptxlator.DptXlator2ByteSigned; - -/** - * This class provides the units for values depending on the DPT (if available) - * - * @author Jan N. Klug - Initial contribution - */ -@NonNullByDefault -public class DPTUnits { - private static final Map DPT_UNIT_MAP = new HashMap<>(); - - private DPTUnits() { - // prevent instantiation - } - - /** - * get unit string for a given DPT - * - * @param dptId the KNX DPT - * @return unit string - */ - public static @Nullable String getUnitForDpt(String dptId) { - return DPT_UNIT_MAP.get(dptId); - } - - /** - * for testing purposes only - * - * @return stream of all unit strings - */ - static Stream getAllUnitStrings() { - return DPT_UNIT_MAP.values().stream(); - } - - static { - // try to get units from Calimeros "unit" field in DPTXlators - List> translators = List.of(DPTXlator2ByteUnsigned.class, DptXlator2ByteSigned.class, - DPTXlator2ByteFloat.class, DPTXlator4ByteUnsigned.class, DPTXlator4ByteSigned.class, - DPTXlator4ByteFloat.class, DPTXlator64BitSigned.class); - - for (Class translator : translators) { - Field[] fields = translator.getFields(); - for (Field field : fields) { - try { - Object o = field.get(null); - if (o instanceof DPT) { - DPT dpt = (DPT) o; - String unit = dpt.getUnit().replaceAll(" ", ""); - // Calimero provides some units (like "ms⁻²") that can't be parsed by our library because of the - // negative exponent - // replace with / - int index = unit.indexOf("⁻"); - if (index != -1) { - unit = unit.substring(0, index - 1) + "/" + unit.substring(index - 1).replace("⁻", ""); - } - if (!unit.isEmpty()) { - DPT_UNIT_MAP.put(dpt.getID(), unit); - } - } - } catch (IllegalAccessException e) { - // ignore errors - } - } - } - - // override/fix units where Calimero data is unparsable or missing - - // 8 bit unsigned (DPT 5) - DPT_UNIT_MAP.put(DPTXlator8BitUnsigned.DPT_SCALING.getID(), Units.PERCENT.getSymbol()); - DPT_UNIT_MAP.put(DPTXlator8BitUnsigned.DPT_PERCENT_U8.getID(), Units.PERCENT.getSymbol()); - - // 8bit signed (DPT 6) - DPT_UNIT_MAP.put(DPTXlator8BitSigned.DPT_PERCENT_V8.getID(), Units.PERCENT.getSymbol()); - - // two byte unsigned (DPT 7) - DPT_UNIT_MAP.remove(DPTXlator2ByteUnsigned.DPT_VALUE_2_UCOUNT.getID()); // counts have no unit - - // two byte signed (DPT 8) - DPT_UNIT_MAP.remove(DptXlator2ByteSigned.DptValueCount.getID()); // pulses habe no unit - - // 4 byte unsigned (DPT 12) - DPT_UNIT_MAP.put(DPTXlator4ByteUnsigned.DptVolumeLiquid.getID(), Units.LITRE.toString()); - DPT_UNIT_MAP.remove(DPTXlator4ByteUnsigned.DPT_VALUE_4_UCOUNT.getID()); // counts have no unit - - // 4 byte signed (DPT 13) - DPT_UNIT_MAP.put(DPTXlator4ByteSigned.DPT_ACTIVE_ENERGY_KWH.getID(), Units.KILOWATT_HOUR.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteSigned.DPT_REACTIVE_ENERGY.getID(), Units.VAR_HOUR.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteSigned.DPT_REACTIVE_ENERGY_KVARH.getID(), Units.KILOVAR_HOUR.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteSigned.DPT_APPARENT_ENERGY_KVAH.getID(), Units.KILOVOLT_AMPERE.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteSigned.DPT_FLOWRATE.getID(), Units.CUBICMETRE_PER_HOUR.toString()); - DPT_UNIT_MAP.remove(DPTXlator4ByteSigned.DPT_COUNT.getID()); // counts have no unit - - // four byte float (DPT 14) - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_CONDUCTANCE.getID(), Units.SIEMENS.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ANGULAR_MOMENTUM.getID(), - Units.JOULE.multiply(Units.SECOND).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ACTIVITY.getID(), Units.BECQUEREL.toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ELECTRICAL_CONDUCTIVITY.getID(), - Units.SIEMENS.divide(SIUnits.METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_TORQUE.getID(), Units.NEWTON.multiply(SIUnits.METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_RESISTIVITY.getID(), Units.OHM.multiply(SIUnits.METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ELECTRIC_DIPOLEMOMENT.getID(), - Units.COULOMB.multiply(SIUnits.METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ELECTRIC_FLUX.getID(), Units.VOLT.multiply(SIUnits.METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_MAGNETIC_MOMENT.getID(), - Units.AMPERE.multiply(SIUnits.SQUARE_METRE).toString()); - DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ELECTROMAGNETIC_MOMENT.getID(), - Units.AMPERE.multiply(SIUnits.SQUARE_METRE).toString()); - - // 64 bit signed (DPT 29) - DPT_UNIT_MAP.put(DPTXlator64BitSigned.DPT_REACTIVE_ENERGY.getID(), Units.VAR_HOUR.toString()); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUtil.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUtil.java deleted file mode 100644 index b428ba66cf..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/DPTUtil.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.dpt; - -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StopMoveType; -import org.openhab.core.library.types.StringType; -import org.openhab.core.library.types.UpDownType; -import org.openhab.core.types.Type; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitSigned; -import tuwien.auto.calimero.dptxlator.DPTXlator8BitUnsigned; -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; -import tuwien.auto.calimero.dptxlator.DPTXlatorString; - -/** - * This class provides support to determine compatibility between KNX DPTs and openHAB data types - * - * Parts of this code are based on the openHAB KNXCoreTypeMapper by Kai Kreuzer et al. - * - * @author Jan N. Klug - Initial contribution - */ -@NonNullByDefault -public class DPTUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(DPTUtil.class); - - // DPT: "123.001", 1-3 digits main type (no leading zero), optional sub-type 3-4 digits (leading zeros allowed) - public static final Pattern DPT_PATTERN = Pattern.compile("^(?
[1-9][0-9]{0,2})(?:\\.(?\\d{3,5}))?$"); - - // used to map vendor-specific data to standard DPT - public static final Map NORMALIZED_DPT = Map.of(// - "232.60000", "232.600"); - - // fall back if no specific type is defined in DPT_TYPE_MAP - private static final Map>> DPT_MAIN_TYPE_MAP = Map.ofEntries( // - Map.entry("1", Set.of(OnOffType.class)), // - Map.entry("2", Set.of(DecimalType.class)), // - Map.entry("3", Set.of(IncreaseDecreaseType.class)), // - Map.entry("4", Set.of(StringType.class)), // - Map.entry("5", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("6", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("7", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("8", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("9", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("10", Set.of(DateTimeType.class)), // - Map.entry("11", Set.of(DateTimeType.class)), // - Map.entry("12", Set.of(DecimalType.class)), // - Map.entry("13", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("14", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("16", Set.of(StringType.class)), // - Map.entry("17", Set.of(DecimalType.class)), // - Map.entry("18", Set.of(DecimalType.class)), // - Map.entry("19", Set.of(DateTimeType.class)), // - Map.entry("20", Set.of(StringType.class)), // - Map.entry("21", Set.of(StringType.class)), // - Map.entry("22", Set.of(StringType.class)), // - Map.entry("28", Set.of(StringType.class)), // - Map.entry("29", Set.of(QuantityType.class, DecimalType.class)), // - Map.entry("229", Set.of(DecimalType.class)), // - Map.entry("232", Set.of(HSBType.class)), // - Map.entry("242", Set.of(HSBType.class)), // - Map.entry("251", Set.of(HSBType.class, PercentType.class))); - - // compatible types for full DPTs - private static final Map>> DPT_TYPE_MAP = Map.ofEntries( - Map.entry(DPTXlatorBoolean.DPT_UPDOWN.getID(), Set.of(UpDownType.class)), // - Map.entry(DPTXlatorBoolean.DPT_OPENCLOSE.getID(), Set.of(OpenClosedType.class)), // - Map.entry(DPTXlatorBoolean.DPT_START.getID(), Set.of(StopMoveType.class)), // - Map.entry(DPTXlatorBoolean.DPT_WINDOW_DOOR.getID(), Set.of(OpenClosedType.class)), // - Map.entry(DPTXlatorBoolean.DPT_SCENE_AB.getID(), Set.of(DecimalType.class)), // - Map.entry(DPTXlator3BitControlled.DPT_CONTROL_BLINDS.getID(), Set.of(UpDownType.class)), // - Map.entry(DPTXlator8BitUnsigned.DPT_SCALING.getID(), - Set.of(QuantityType.class, DecimalType.class, PercentType.class)), // - Map.entry(DPTXlator8BitSigned.DPT_STATUS_MODE3.getID(), Set.of(StringType.class)), // - Map.entry(DPTXlatorString.DPT_STRING_8859_1.getID(), Set.of(StringType.class)), // - Map.entry(DPTXlatorString.DPT_STRING_ASCII.getID(), Set.of(StringType.class))); - - private DPTUtil() { - // prevent instantiation - } - - /** - * get allowed openHAB types for given DPT - * - * @param dptId the datapoint type id - * @return Set of supported openHAB types (command or state) - */ - public static Set> getAllowedTypes(String dptId) { - Set> allowedTypes = DPT_TYPE_MAP.get(dptId); - if (allowedTypes == null) { - Matcher m = DPT_PATTERN.matcher(dptId); - if (!m.matches()) { - LOGGER.warn("getAllowedTypes couldn't identify main number in dptID '{}'", dptId); - return Set.of(); - } - - allowedTypes = DPT_MAIN_TYPE_MAP.getOrDefault(m.group("main"), Set.of()); - } - return allowedTypes; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueDecoder.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueDecoder.java deleted file mode 100644 index 7f17c0b5a6..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueDecoder.java +++ /dev/null @@ -1,374 +0,0 @@ -/** - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.dpt; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.DISABLE_UOM; - -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Locale; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StopMoveType; -import org.openhab.core.library.types.StringType; -import org.openhab.core.library.types.UpDownType; -import org.openhab.core.types.Type; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.commons.util.ColorUtil; - -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.KNXFormatException; -import tuwien.auto.calimero.KNXIllegalArgumentException; -import tuwien.auto.calimero.dptxlator.DPTXlator; -import tuwien.auto.calimero.dptxlator.DPTXlator1BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean; -import tuwien.auto.calimero.dptxlator.DPTXlatorDateTime; -import tuwien.auto.calimero.dptxlator.DPTXlatorSceneControl; -import tuwien.auto.calimero.dptxlator.TranslatorTypes; - -/** - * This class decodes raw data received from the KNX bus to an openHAB datatype - * - * Parts of this code are based on the openHAB KNXCoreTypeMapper by Kai Kreuzer et al. - * - * @author Jan N. Klug - Initial contribution - */ -@NonNullByDefault -public class ValueDecoder { - private static final Logger LOGGER = LoggerFactory.getLogger(ValueDecoder.class); - - private static final String TIME_DAY_FORMAT = "EEE, HH:mm:ss"; - private static final String DATE_FORMAT = "yyyy-MM-dd"; - // RGB: "r:123 g:123 b:123" value-range: 0-255 - private static final Pattern RGB_PATTERN = Pattern.compile("r:(?\\d+) g:(?\\d+) b:(?\\d+)"); - // RGBW: "100 27 25 12 %", value range: 0-100, invalid values: "-" - private static final Pattern RGBW_PATTERN = Pattern - .compile("(?:(?[\\d,.]+)|-)\\s(?:(?[\\d,.]+)|-)\\s(?:(?[\\d,.]+)|-)\\s(?:(?[\\d,.]+)|-)\\s%"); - // xyY: "(0,123 0,123) 56 %", value range 0-1 for xy (comma as decimal point), 0-100 for Y, invalid values omitted - private static final Pattern XYY_PATTERN = Pattern - .compile("(?:\\((?\\d+(?:,\\d+)?) (?\\d+(?:,\\d+)?)\\))?\\s*(?:(?\\d+(?:,\\d+)?)\\s%)?"); - - /** - * convert the raw value received to the corresponding openHAB value - * - * @param dptId the DPT of the given data - * @param data a byte array containing the value - * @param preferredType the preferred datatype for this conversion - * @return the data converted to an openHAB Type (or null if conversion failed) - */ - public static @Nullable Type decode(String dptId, byte[] data, Class preferredType) { - try { - DPTXlator translator = TranslatorTypes.createTranslator(0, - DPTUtil.NORMALIZED_DPT.getOrDefault(dptId, dptId)); - translator.setData(data); - String value = translator.getValue(); - - String id = dptId; // prefer using the user-supplied DPT - - Matcher m = DPTUtil.DPT_PATTERN.matcher(id); - if (!m.matches() || m.groupCount() != 2) { - LOGGER.trace("User-Supplied DPT '{}' did not match for sub-type, using DPT returned from Translator", - id); - id = translator.getType().getID(); - m = DPTUtil.DPT_PATTERN.matcher(id); - if (!m.matches() || m.groupCount() != 2) { - LOGGER.warn("couldn't identify main/sub number in dptID '{}'", id); - return null; - } - } - LOGGER.trace("Finally using datapoint DPT = {}", id); - - String mainType = m.group("main"); - String subType = m.group("sub"); - - switch (mainType) { - case "1": - return handleDpt1(subType, translator); - case "2": - DPTXlator1BitControlled translator1BitControlled = (DPTXlator1BitControlled) translator; - int decValue = (translator1BitControlled.getControlBit() ? 2 : 0) - + (translator1BitControlled.getValueBit() ? 1 : 0); - return new DecimalType(decValue); - case "3": - return handleDpt3(subType, translator); - case "10": - return handleDpt10(value); - case "11": - return DateTimeType.valueOf(new SimpleDateFormat(DateTimeType.DATE_PATTERN) - .format(new SimpleDateFormat(DATE_FORMAT).parse(value))); - case "18": - DPTXlatorSceneControl translatorSceneControl = (DPTXlatorSceneControl) translator; - int decimalValue = translatorSceneControl.getSceneNumber(); - if (value.startsWith("learn")) { - decimalValue += 0x80; - } - return new DecimalType(decimalValue); - case "19": - return handleDpt19(translator); - case "16": - case "20": - case "21": - case "22": - case "28": - return StringType.valueOf(value); - case "232": - return handleDpt232(value, subType); - case "242": - return handleDpt242(value); - case "251": - return handleDpt251(value, preferredType); - default: - return handleNumericDpt(id, translator, preferredType); - } - } catch (NumberFormatException | KNXFormatException | KNXIllegalArgumentException | ParseException e) { - LOGGER.info("Translator couldn't parse data '{}' for datapoint type '{}' ({}).", data, dptId, e.getClass()); - } catch (KNXException e) { - LOGGER.warn("Failed creating a translator for datapoint type '{}'.", dptId, e); - } - - return null; - } - - private static Type handleDpt1(String subType, DPTXlator translator) { - DPTXlatorBoolean translatorBoolean = (DPTXlatorBoolean) translator; - switch (subType) { - case "008": - return translatorBoolean.getValueBoolean() ? UpDownType.DOWN : UpDownType.UP; - case "009": - case "019": - // This is wrong for DPT 1.009. It should be true -> CLOSE, false -> OPEN, but unfortunately - // can't be fixed without breaking a lot of working installations. - // The documentation has been updated to reflect that. / @J-N-K - return translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED; - case "010": - return translatorBoolean.getValueBoolean() ? StopMoveType.MOVE : StopMoveType.STOP; - case "022": - return DecimalType.valueOf(translatorBoolean.getValueBoolean() ? "1" : "0"); - default: - return OnOffType.from(translatorBoolean.getValueBoolean()); - } - } - - private static @Nullable Type handleDpt3(String subType, DPTXlator translator) { - DPTXlator3BitControlled translator3BitControlled = (DPTXlator3BitControlled) translator; - if (translator3BitControlled.getStepCode() == 0) { - LOGGER.debug("convertRawDataToType: KNX DPT_Control_Dimming: break received."); - return UnDefType.NULL; - } - switch (subType) { - case "007": - return translator3BitControlled.getControlBit() ? IncreaseDecreaseType.INCREASE - : IncreaseDecreaseType.DECREASE; - case "008": - return translator3BitControlled.getControlBit() ? UpDownType.DOWN : UpDownType.UP; - default: - LOGGER.warn("DPT3, subtype '{}' is unknown.", subType); - return null; - } - } - - private static Type handleDpt10(String value) throws ParseException { - if (value.contains("no-day")) { - /* - * KNX "no-day" needs special treatment since openHAB's DateTimeType doesn't support "no-day". - * Workaround: remove the "no-day" String, parse the remaining time string, which will result in a - * date of "1970-01-01". - * Replace "no-day" with the current day name - */ - StringBuilder stb = new StringBuilder(value); - int start = stb.indexOf("no-day"); - int end = start + "no-day".length(); - stb.replace(start, end, String.format(Locale.US, "%1$ta", Calendar.getInstance())); - value = stb.toString(); - } - return DateTimeType.valueOf(new SimpleDateFormat(DateTimeType.DATE_PATTERN) - .format(new SimpleDateFormat(TIME_DAY_FORMAT, Locale.US).parse(value))); - } - - private static @Nullable Type handleDpt19(DPTXlator translator) throws KNXFormatException { - DPTXlatorDateTime translatorDateTime = (DPTXlatorDateTime) translator; - if (translatorDateTime.isFaultyClock()) { - // Not supported: faulty clock - LOGGER.debug("KNX clock msg ignored: clock faulty bit set, which is not supported"); - return null; - } else if (!translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && translatorDateTime.isValidField(DPTXlatorDateTime.DATE)) { - // Not supported: "/1/1" (month and day without year) - LOGGER.debug("KNX clock msg ignored: no year, but day and month, which is not supported"); - return null; - } else if (translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && !translatorDateTime.isValidField(DPTXlatorDateTime.DATE)) { - // Not supported: "1900" (year without month and day) - LOGGER.debug("KNX clock msg ignored: no day and month, but year, which is not supported"); - return null; - } else if (!translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && !translatorDateTime.isValidField(DPTXlatorDateTime.DATE) - && !translatorDateTime.isValidField(DPTXlatorDateTime.TIME)) { - // Not supported: No year, no date and no time - LOGGER.debug("KNX clock msg ignored: no day and month or year, which is not supported"); - return null; - } - - Calendar cal = Calendar.getInstance(); - if (translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && !translatorDateTime.isValidField(DPTXlatorDateTime.TIME)) { - // Pure date format, no time information - cal.setTimeInMillis(translatorDateTime.getValueMilliseconds()); - String value = new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(cal.getTime()); - return DateTimeType.valueOf(value); - } else if (!translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && translatorDateTime.isValidField(DPTXlatorDateTime.TIME)) { - // Pure time format, no date information - cal.clear(); - cal.set(Calendar.HOUR_OF_DAY, translatorDateTime.getHour()); - cal.set(Calendar.MINUTE, translatorDateTime.getMinute()); - cal.set(Calendar.SECOND, translatorDateTime.getSecond()); - String value = new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(cal.getTime()); - return DateTimeType.valueOf(value); - } else if (translatorDateTime.isValidField(DPTXlatorDateTime.YEAR) - && translatorDateTime.isValidField(DPTXlatorDateTime.TIME)) { - // Date format and time information - cal.setTimeInMillis(translatorDateTime.getValueMilliseconds()); - String value = new SimpleDateFormat(DateTimeType.DATE_PATTERN).format(cal.getTime()); - return DateTimeType.valueOf(value); - } else { - LOGGER.warn("Failed to convert '{}'", translator.getValue()); - return null; - } - } - - private static @Nullable Type handleDpt232(String value, String subType) { - Matcher rgb = RGB_PATTERN.matcher(value); - if (rgb.matches()) { - int r = Integer.parseInt(rgb.group("r")); - int g = Integer.parseInt(rgb.group("g")); - int b = Integer.parseInt(rgb.group("b")); - - switch (subType) { - case "600": - return HSBType.fromRGB(r, g, b); - case "60000": - // MDT specific: mis-use 232.600 for hsv instead of rgb - DecimalType hue = new DecimalType(coerceToRange(r * 360.0 / 255.0, 0.0, 359.9999)); - PercentType sat = new PercentType(BigDecimal.valueOf(coerceToRange(g / 2.55, 0.0, 100.0))); - PercentType bright = new PercentType(BigDecimal.valueOf(coerceToRange(b / 2.55, 0.0, 100.0))); - return new HSBType(hue, sat, bright); - default: - LOGGER.warn("Unknown subtype '232.{}', no conversion possible.", subType); - return null; - } - } - LOGGER.warn("Failed to convert '{}' (DPT 232): Pattern does not match", value); - return null; - } - - private static @Nullable Type handleDpt242(String value) { - Matcher xyY = XYY_PATTERN.matcher(value); - if (xyY.matches()) { - String xString = xyY.group("x"); - String yString = xyY.group("y"); - String YString = xyY.group("Y"); - - if (xString != null && yString != null) { - double x = Double.parseDouble(xString.replace(",", ".")); - double y = Double.parseDouble(yString.replace(",", ".")); - if (YString == null) { - return ColorUtil.xyToHsv(new double[] { x, y }); - } else { - double Y = Double.parseDouble(YString.replace(",", ".")); - return ColorUtil.xyToHsv(new double[] { x, y, Y }); - } - } - } - LOGGER.warn("Failed to convert '{}' (DPT 242): Pattern does not match", value); - return null; - } - - private static @Nullable Type handleDpt251(String value, Class preferredType) { - Matcher rgbw = RGBW_PATTERN.matcher(value); - if (rgbw.matches()) { - String rString = rgbw.group("r"); - String gString = rgbw.group("g"); - String bString = rgbw.group("b"); - String wString = rgbw.group("w"); - - if (rString != null && gString != null && bString != null && HSBType.class.equals(preferredType)) { - // does not support PercentType and r,g,b valid -> HSBType - int r = coerceToRange((int) (Double.parseDouble(rString.replace(",", ".")) * 2.55), 0, 255); - int g = coerceToRange((int) (Double.parseDouble(gString.replace(",", ".")) * 2.55), 0, 255); - int b = coerceToRange((int) (Double.parseDouble(bString.replace(",", ".")) * 2.55), 0, 255); - - return HSBType.fromRGB(r, g, b); - } else if (wString != null && PercentType.class.equals(preferredType)) { - // does support PercentType and w valid -> PercentType - BigDecimal w = new BigDecimal(wString.replace(",", ".")); - - return new PercentType(w); - } - } - LOGGER.warn("Failed to convert '{}' (DPT 251): Pattern does not match or invalid content", value); - return null; - } - - private static @Nullable Type handleNumericDpt(String id, DPTXlator translator, Class preferredType) - throws KNXFormatException { - Set> allowedTypes = DPTUtil.getAllowedTypes(id); - - double value = translator.getNumericValue(); - if (allowedTypes.contains(PercentType.class) - && (HSBType.class.equals(preferredType) || PercentType.class.equals(preferredType))) { - return new PercentType(BigDecimal.valueOf(Math.round(value))); - } - - if (allowedTypes.contains(QuantityType.class) && !DISABLE_UOM) { - String unit = DPTUnits.getUnitForDpt(id); - if (unit != null) { - return new QuantityType<>(value + " " + unit); - } else { - LOGGER.trace("Could not determine unit for DPT '{}', fallback to plain decimal", id); - } - } - - if (allowedTypes.contains(DecimalType.class)) { - return new DecimalType(value); - } - - LOGGER.warn("Failed to convert '{}' (DPT '{}'): no matching type found", value, id); - return null; - } - - private static double coerceToRange(double value, double min, double max) { - return Math.min(Math.max(value, min), max); - } - - private static int coerceToRange(int value, int min, int max) { - return Math.min(Math.max(value, min), max); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueEncoder.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueEncoder.java deleted file mode 100644 index aa9b086a6a..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/dpt/ValueEncoder.java +++ /dev/null @@ -1,224 +0,0 @@ -/** - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.dpt; - -import static org.smarthomej.binding.knx.internal.dpt.DPTUtil.NORMALIZED_DPT; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.Locale; -import java.util.regex.Matcher; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.OpenClosedType; -import org.openhab.core.library.types.PercentType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StopMoveType; -import org.openhab.core.library.types.StringType; -import org.openhab.core.library.types.UpDownType; -import org.openhab.core.types.Type; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.commons.util.ColorUtil; - -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.dptxlator.DPT; -import tuwien.auto.calimero.dptxlator.DPTXlator; -import tuwien.auto.calimero.dptxlator.DPTXlator1BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlator3BitControlled; -import tuwien.auto.calimero.dptxlator.DPTXlatorDate; -import tuwien.auto.calimero.dptxlator.DPTXlatorDateTime; -import tuwien.auto.calimero.dptxlator.DPTXlatorTime; -import tuwien.auto.calimero.dptxlator.TranslatorTypes; - -/** - * This class encodes openHAB data types to strings for sending via Calimero - * - * Parts of this code are based on the openHAB KNXCoreTypeMapper by Kai Kreuzer et al. - * - * @author Jan N. Klug - Initial contribution - */ -@NonNullByDefault -public class ValueEncoder { - private static final Logger LOGGER = LoggerFactory.getLogger(ValueEncoder.class); - - private ValueEncoder() { - // prevent instantiation - } - - /** - * formats the given value as String for outputting via Calimero - * - * @param value the value - * @param dptId the DPT id to use for formatting the string (e.g. 9.001) - * @return the value formatted as String - */ - public static @Nullable String encode(Type value, String dptId) { - Matcher m = DPTUtil.DPT_PATTERN.matcher(dptId); - if (!m.matches() || m.groupCount() != 2) { - LOGGER.warn("couldn't identify main/sub number in dptId '{}'", dptId); - return null; - } - - String mainNumber = m.group("main"); - - try { - DPTXlator translator = TranslatorTypes.createTranslator(Integer.parseInt(mainNumber), - NORMALIZED_DPT.getOrDefault(dptId, dptId)); - DPT dpt = translator.getType(); - - // check for HSBType first, because it extends PercentType as well - if (value instanceof HSBType) { - return handleHSBType(dptId, (HSBType) value); - } else if (value instanceof OnOffType) { - return OnOffType.OFF.equals(value) ? dpt.getLowerValue() : dpt.getUpperValue(); - } else if (value instanceof UpDownType) { - return UpDownType.UP.equals(value) ? dpt.getLowerValue() : dpt.getUpperValue(); - } else if (value instanceof IncreaseDecreaseType) { - DPT valueDPT = ((DPTXlator3BitControlled.DPT3BitControlled) dpt).getControlDPT(); - return IncreaseDecreaseType.DECREASE.equals(value) ? valueDPT.getLowerValue() + " 5" - : valueDPT.getUpperValue() + " 5"; - } else if (value instanceof OpenClosedType) { - return OpenClosedType.CLOSED.equals(value) ? dpt.getLowerValue() : dpt.getUpperValue(); - } else if (value instanceof StopMoveType) { - return StopMoveType.STOP.equals(value) ? dpt.getLowerValue() : dpt.getUpperValue(); - } else if (value instanceof PercentType) { - int intValue = ((PercentType) value).intValue(); - return "251.600".equals(dptId) ? String.format("- - - %d %%", intValue) : String.valueOf(intValue); - } else if (value instanceof DecimalType || value instanceof QuantityType) { - return handleNumericTypes(dptId, mainNumber, dpt, value); - } else if (value instanceof StringType) { - return value.toString(); - } else if (value instanceof DateTimeType) { - return handleDateTimeType(dptId, (DateTimeType) value); - } - } catch (KNXException e) { - return null; - } catch (Exception e) { - LOGGER.warn("An exception occurred converting value {} to dpt id {}: error message={}", value, dptId, - e.getMessage()); - return null; - } - - LOGGER.debug("formatAsDPTString: Couldn't convert value {} to dpt id {} (no mapping).", value, dptId); - return null; - } - - /** - * Formats the given internal dateType to a knx readable String - * according to the target datapoint type dpt. - * - * @param value the input value - * @param dptId the target datapoint type - * - * @return a String which contains either an ISO8601 formatted date (yyyy-mm-dd), - * a formatted 24-hour clock with the day of week prepended (Mon, 12:00:00) or - * a formatted 24-hour clock (12:00:00) - */ - private static @Nullable String handleDateTimeType(String dptId, DateTimeType value) { - if (DPTXlatorDate.DPT_DATE.getID().equals(dptId)) { - return value.format("%tF"); - } else if (DPTXlatorTime.DPT_TIMEOFDAY.getID().equals(dptId)) { - return value.format(Locale.US, "%1$ta, %1$tT"); - } else if (DPTXlatorDateTime.DPT_DATE_TIME.getID().equals(dptId)) { - return value.format(Locale.US, "%tF %1$tT"); - } - LOGGER.warn("Could not format DateTimeType for datapoint type '{}'", dptId); - return null; - } - - private static String handleHSBType(String dptId, HSBType hsb) { - switch (dptId) { - case "232.600": - return "r:" + convertPercentToByte(hsb.getRed()) + " g:" + convertPercentToByte(hsb.getGreen()) + " b:" - + convertPercentToByte(hsb.getBlue()); - case "232.60000": - // MDT specific: mis-use 232.600 for hsv instead of rgb - int hue = hsb.getHue().toBigDecimal().multiply(BigDecimal.valueOf(255)) - .divide(BigDecimal.valueOf(360), 2, RoundingMode.HALF_UP).intValue(); - return "r:" + hue + " g:" + convertPercentToByte(hsb.getSaturation()) + " b:" - + convertPercentToByte(hsb.getBrightness()); - case "242.600": - double[] xyY = ColorUtil.hsbToXY(hsb); - return String.format("(%,.4f %,.4f) %,.1f %%", xyY[0], xyY[1], xyY[2] * 100.0); - case "251.600": - return String.format("%d %d %d - %%", hsb.getRed().intValue(), hsb.getGreen().intValue(), - hsb.getBlue().intValue()); - case "5.003": - return hsb.getHue().toString(); - default: - return hsb.getBrightness().toString(); - } - } - - private static String handleNumericTypes(String dptId, String mainNumber, DPT dpt, Type value) { - BigDecimal bigDecimal; - if (value instanceof DecimalType) { - bigDecimal = ((DecimalType) value).toBigDecimal(); - } else { - String unit = DPTUnits.getUnitForDpt(dptId); - if (unit != null) { - QuantityType converted = ((QuantityType) value).toUnit(unit); - if (converted == null) { - LOGGER.warn("Could not convert {} to unit {}, stripping unit only. Check your configuration.", - value, unit); - bigDecimal = ((QuantityType) value).toBigDecimal(); - } else { - bigDecimal = converted.toBigDecimal(); - } - } else { - bigDecimal = ((QuantityType) value).toBigDecimal(); - } - } - switch (mainNumber) { - case "2": - DPT valueDPT = ((DPTXlator1BitControlled.DPT1BitControlled) dpt).getValueDPT(); - switch (bigDecimal.intValue()) { - case 0: - return "0 " + valueDPT.getLowerValue(); - case 1: - return "0 " + valueDPT.getUpperValue(); - case 2: - return "1 " + valueDPT.getLowerValue(); - default: - return "1 " + valueDPT.getUpperValue(); - } - case "18": - int intVal = bigDecimal.intValue(); - if (intVal > 63) { - return "learn " + (intVal - 0x80); - } else { - return "activate " + intVal; - } - default: - return bigDecimal.stripTrailingZeros().toPlainString(); - } - } - - /** - * convert 0...100% to 1 byte 0..255 - * - * @param percent - * @return int 0..255 - */ - private static int convertPercentToByte(PercentType percent) { - return percent.toBigDecimal().multiply(BigDecimal.valueOf(255)) - .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).intValue(); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/factory/KNXHandlerFactory.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/factory/KNXHandlerFactory.java deleted file mode 100644 index fb70c16c53..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/factory/KNXHandlerFactory.java +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.factory; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.config.core.Configuration; -import org.openhab.core.net.NetworkAddressService; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.thing.ThingUID; -import org.openhab.core.thing.binding.BaseThingHandlerFactory; -import org.openhab.core.thing.binding.ThingHandler; -import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Modified; -import org.osgi.service.component.annotations.Reference; -import org.smarthomej.binding.knx.internal.handler.DeviceThingHandler; -import org.smarthomej.binding.knx.internal.handler.IPBridgeThingHandler; -import org.smarthomej.binding.knx.internal.handler.SerialBridgeThingHandler; - -/** - * The {@link KNXHandlerFactory} is responsible for creating things and thing - * handlers. - * - * @author Simon Kaufmann - Initial contribution and API - */ -@NonNullByDefault -@Component(service = ThingHandlerFactory.class, configurationPid = "binding.knx") -public class KNXHandlerFactory extends BaseThingHandlerFactory { - - public static final Collection SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_DEVICE, - THING_TYPE_IP_BRIDGE, THING_TYPE_SERIAL_BRIDGE); - - private final NetworkAddressService networkAddressService; - - @Activate - public KNXHandlerFactory(@Reference NetworkAddressService networkAddressService, Map config) { - this.networkAddressService = networkAddressService; - modified(config); - } - - @Modified - protected void modified(Map config) { - DISABLE_UOM = (boolean) config.getOrDefault(CONFIG_DISABLE_UOM, false); - } - - @Override - public boolean supportsThingType(ThingTypeUID thingTypeUID) { - return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); - } - - @Override - public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, - @Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) { - if (THING_TYPE_IP_BRIDGE.equals(thingTypeUID)) { - ThingUID ipBridgeThingUID = getIPBridgeThingUID(thingTypeUID, thingUID, configuration); - return super.createThing(thingTypeUID, configuration, ipBridgeThingUID, null); - } - if (THING_TYPE_SERIAL_BRIDGE.equals(thingTypeUID)) { - ThingUID serialBridgeUID = getSerialBridgeThingUID(thingTypeUID, thingUID, configuration); - return super.createThing(thingTypeUID, configuration, serialBridgeUID, null); - } - if (THING_TYPE_DEVICE.equals(thingTypeUID)) { - return super.createThing(thingTypeUID, configuration, thingUID, bridgeUID); - } - return null; - } - - @Override - protected @Nullable ThingHandler createHandler(Thing thing) { - if (thing.getThingTypeUID().equals(THING_TYPE_IP_BRIDGE)) { - return new IPBridgeThingHandler((Bridge) thing, networkAddressService); - } else if (thing.getThingTypeUID().equals(THING_TYPE_SERIAL_BRIDGE)) { - return new SerialBridgeThingHandler((Bridge) thing); - } else if (thing.getThingTypeUID().equals(THING_TYPE_DEVICE)) { - return new DeviceThingHandler(thing); - } - return null; - } - - private ThingUID getIPBridgeThingUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, - Configuration configuration) { - if (thingUID != null) { - return thingUID; - } - String ipAddress = (String) configuration.get(IP_ADDRESS); - return new ThingUID(thingTypeUID, ipAddress); - } - - private ThingUID getSerialBridgeThingUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, - Configuration configuration) { - if (thingUID != null) { - return thingUID; - } - String serialPort = (String) configuration.get(SERIAL_PORT); - return new ThingUID(thingTypeUID, serialPort); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceConstants.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceConstants.java deleted file mode 100644 index 38b6beb47c..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceConstants.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * @author Karel Goderis - Initial contribution - */ -@NonNullByDefault -public class DeviceConstants { - - private DeviceConstants() { - // prevent instantiation - } - - // Memory addresses for device information - public static final int MEM_DOA = 0x0102; // length 2 - public static final int MEM_MANUFACTURERID = 0x0104; - public static final int MEM_DEVICETYPE = 0x0105; // length 2 - public static final int MEM_VERSION = 0x0107; - public static final int MEM_PEI = 0x0109; - public static final int MEM_RUNERROR = 0x010d; - public static final int MEM_GROUPOBJECTABLEPTR = 0x0112; - public static final int MEM_PROGRAMPTR = 0x0114; - public static final int MEM_GROUPADDRESSTABLE = 0x0116; // max. length 233 - - // Interface Object indexes - public static final int DEVICE_OBJECT = 0; // Device Object - public static final int ADDRESS_TABLE_OBJECT = 1; // Addresstable Object - public static final int ASSOCIATION_TABLE_OBJECT = 2; // Associationtable Object - public static final int APPLICATION_PROGRAM_TABLE = 3; // Application Program Object - public static final int INTERFACE_PROGRAM_OBJECT = 4; // Interface Program Object - public static final int GROUPOBJECT_OBJECT = 9; // Group Object Object - public static final int KNXNET_IP_OBJECT = 11; // KNXnet/IP Parameter Object - - // Property IDs for device information; - public static final int HARDWARE_TYPE = 78; -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceThingHandler.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceThingHandler.java deleted file mode 100644 index a12733cdfe..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/DeviceThingHandler.java +++ /dev/null @@ -1,527 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import java.math.BigDecimal; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.cache.ExpiringCacheMap; -import org.openhab.core.library.types.IncreaseDecreaseType; -import org.openhab.core.thing.Bridge; -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.thing.ThingStatusInfo; -import org.openhab.core.thing.binding.BaseThingHandler; -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.openhab.core.types.UnDefType; -import org.openhab.core.util.HexUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.binding.knx.internal.KNXBindingConstants; -import org.smarthomej.binding.knx.internal.channel.KNXChannel; -import org.smarthomej.binding.knx.internal.channel.KNXChannelFactory; -import org.smarthomej.binding.knx.internal.client.AbstractKNXClient; -import org.smarthomej.binding.knx.internal.client.DeviceInspector; -import org.smarthomej.binding.knx.internal.client.InboundSpec; -import org.smarthomej.binding.knx.internal.client.KNXClient; -import org.smarthomej.binding.knx.internal.client.OutboundSpec; -import org.smarthomej.binding.knx.internal.config.DeviceConfig; -import org.smarthomej.binding.knx.internal.dpt.DPTUtil; -import org.smarthomej.binding.knx.internal.dpt.ValueDecoder; - -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.KNXException; -import tuwien.auto.calimero.KNXFormatException; -import tuwien.auto.calimero.datapoint.CommandDP; -import tuwien.auto.calimero.datapoint.Datapoint; - -/** - * The {@link DeviceThingHandler} is responsible for handling commands and state updates sent to and received from the - * bus and updating the channels correspondingly. - * - * @author Simon Kaufmann - Initial contribution and API - * @author Jan N. Klug - Refactored for performance - */ -@NonNullByDefault -public class DeviceThingHandler extends BaseThingHandler implements GroupAddressListener { - private static final int INITIAL_PING_DELAY = 5; - private final Logger logger = LoggerFactory.getLogger(DeviceThingHandler.class); - - private final Set groupAddresses = ConcurrentHashMap.newKeySet(); - private final ExpiringCacheMap groupAddressesWriteBlocked = new ExpiringCacheMap<>( - Duration.ofMillis(1000)); - private final Map groupAddressesRespondingSpec = new ConcurrentHashMap<>(); - private final Map> readFutures = new ConcurrentHashMap<>(); - private final Map> channelFutures = new ConcurrentHashMap<>(); - private final Map knxChannels = new ConcurrentHashMap<>(); - private final Random random = new Random(); - protected @Nullable IndividualAddress address; - private int readInterval; - private @Nullable ScheduledFuture descriptionJob; - private boolean filledDescription = false; - private @Nullable ScheduledFuture pollingJob; - - public DeviceThingHandler(Thing thing) { - super(thing); - } - - @Override - public void initialize() { - attachToClient(); - - DeviceConfig config = getConfigAs(DeviceConfig.class); - readInterval = config.getReadInterval(); - - // gather all GAs from channel configurations and create channels - getThing().getChannels().forEach(channel -> { - KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel); - knxChannels.put(channel.getUID(), knxChannel); - groupAddresses.addAll(knxChannel.getAllGroupAddresses()); - }); - } - - @Override - public void dispose() { - for (ChannelUID channelUID : channelFutures.keySet()) { - channelFutures.computeIfPresent(channelUID, (k, v) -> { - v.cancel(true); - return null; - }); - } - - groupAddresses.clear(); - groupAddressesWriteBlocked.clear(); - groupAddressesRespondingSpec.clear(); - knxChannels.clear(); - - detachFromClient(); - } - - protected void cancelReadFutures() { - for (GroupAddress groupAddress : readFutures.keySet()) { - readFutures.computeIfPresent(groupAddress, (k, v) -> { - v.cancel(true); - return null; - }); - } - } - - @Override - public void channelLinked(ChannelUID channelUID) { - KNXChannel knxChannel = knxChannels.get(channelUID); - if (knxChannel == null) { - logger.warn("Channel '{}' received a channel linked event, but no KNXChannel found", channelUID); - return; - } - if (!knxChannel.isControl()) { - scheduleRead(knxChannel); - } - } - - protected void scheduleReadJobs() { - cancelReadFutures(); - for (KNXChannel knxChannel : knxChannels.values()) { - if (isLinked(knxChannel.getChannelUID()) && !knxChannel.isControl()) { - scheduleRead(knxChannel); - } - } - } - - private void scheduleRead(KNXChannel knxChannel) { - List readSpecs = knxChannel.getReadSpec(); - for (InboundSpec readSpec : readSpecs) { - readSpec.getGroupAddresses().forEach(ga -> scheduleReadJob(ga, readSpec.getDPT())); - } - } - - private void scheduleReadJob(GroupAddress groupAddress, String dpt) { - if (readInterval > 0) { - ScheduledFuture future = readFutures.get(groupAddress); - if (future == null || future.isDone() || future.isCancelled()) { - future = getScheduler().scheduleWithFixedDelay(() -> readDatapoint(groupAddress, dpt), 0, readInterval, - TimeUnit.SECONDS); - readFutures.put(groupAddress, future); - } - } else { - getScheduler().submit(() -> readDatapoint(groupAddress, dpt)); - } - } - - private void readDatapoint(GroupAddress groupAddress, String dpt) { - if (getClient().isConnected()) { - if (DPTUtil.getAllowedTypes(dpt).isEmpty()) { - logger.warn("DPT '{}' is not supported by the KNX binding", dpt); - return; - } - Datapoint datapoint = new CommandDP(groupAddress, getThing().getUID().toString(), 0, dpt); - getClient().readDatapoint(datapoint); - } - } - - @Override - public boolean listensTo(GroupAddress destination) { - return groupAddresses.contains(destination); - } - - /** Handling commands triggered from openHAB */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - logger.trace("Handling command '{}' for channel '{}'", command, channelUID); - KNXChannel knxChannel = knxChannels.get(channelUID); - if (knxChannel == null) { - logger.warn("Channel '{}' received command, but no KNXChannel found", channelUID); - return; - } - if (command instanceof RefreshType && !knxChannel.isControl()) { - logger.debug("Refreshing channel '{}'", channelUID); - scheduleRead(knxChannel); - } else { - if (CHANNEL_RESET.equals(channelUID.getId())) { - if (address != null) { - restart(); - } - } else { - try { - OutboundSpec commandSpec = knxChannel.getCommandSpec(command); - // only send GroupValueWrite to KNX if GA is not blocked once - if (commandSpec != null) { - GroupAddress destination = commandSpec.getGroupAddress(); - if (knxChannel.isControl()) { - // always remember, otherwise we might send an old state - groupAddressesRespondingSpec.put(destination, commandSpec); - } - if (groupAddressesWriteBlocked.get(destination) != null) { - logger.debug("Write to {} blocked for 1s/one call after read.", destination); - groupAddressesWriteBlocked.invalidate(destination); - } else { - getClient().writeToKNX(commandSpec); - } - } else { - logger.debug( - "None of the configured GAs on channel '{}' could handle the command '{}' of type '{}'", - channelUID, command, command.getClass().getSimpleName()); - } - } catch (KNXException e) { - logger.warn("An error occurred while handling command '{}' on channel '{}': {}", command, - channelUID, e.getMessage()); - } - } - } - } - - /** KNXIO */ - private void sendGroupValueResponse(ChannelUID channelUID, GroupAddress destination) { - KNXChannel knxChannel = knxChannels.get(channelUID); - if (knxChannel == null) { - return; - } - Set rsa = knxChannel.getWriteAddresses(); - if (!rsa.isEmpty()) { - logger.trace("onGroupRead size '{}'", rsa.size()); - OutboundSpec os = groupAddressesRespondingSpec.get(destination); - if (os != null) { - logger.trace("onGroupRead respondToKNX '{}'", os.getGroupAddress()); - /* KNXIO: sending real "GroupValueResponse" to the KNX bus. */ - try { - getClient().respondToKNX(os); - } catch (KNXException e) { - logger.warn("An error occurred on channel {}: {}", channelUID, e.getMessage(), e); - } - } - } - } - - /** - * KNXIO, extended with the ability to respond on "GroupValueRead" telegrams with "GroupValueResponse" telegram - */ - @Override - public void onGroupRead(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, byte[] asdu) { - logger.trace("onGroupRead Thing '{}' received a GroupValueRead telegram from '{}' for destination '{}'", - getThing().getUID(), source, destination); - for (KNXChannel knxChannel : knxChannels.values()) { - if (knxChannel.isControl()) { - OutboundSpec responseSpec = knxChannel.getResponseSpec(destination, RefreshType.REFRESH); - if (responseSpec != null) { - logger.trace("onGroupRead isControl -> postCommand"); - // This event should be sent to KNX as GroupValueResponse immediately. - sendGroupValueResponse(knxChannel.getChannelUID(), destination); - - // block write attempts for 1s or 1 request to prevent loops - if (!groupAddressesWriteBlocked.containsKey(destination)) { - groupAddressesWriteBlocked.put(destination, () -> null); - } - groupAddressesWriteBlocked.putValue(destination, true); - - // Send REFRESH to openHAB to get this event for scripting with postCommand - // and remember to ignore/block this REFRESH to be sent back to KNX as GroupValueWrite after - // postCommand is done! - postCommand(knxChannel.getChannelUID(), RefreshType.REFRESH); - } - } - } - } - - @Override - public void onGroupReadResponse(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, - byte[] asdu) { - // GroupValueResponses are treated the same as GroupValueWrite telegrams - logger.trace("onGroupReadResponse Thing '{}' processes a GroupValueResponse telegram for destination '{}'", - getThing().getUID(), destination); - onGroupWrite(client, source, destination, asdu); - } - - /** - * KNXIO, here value changes are set, coming from KNX OR openHAB. - */ - @Override - public void onGroupWrite(AbstractKNXClient client, IndividualAddress source, GroupAddress destination, - byte[] asdu) { - logger.debug("onGroupWrite Thing '{}' received a GroupValueWrite telegram from '{}' for destination '{}'", - getThing().getUID(), source, destination); - - for (KNXChannel knxChannel : knxChannels.values()) { - InboundSpec listenSpec = knxChannel.getListenSpec(destination); - if (listenSpec != null) { - logger.trace( - "onGroupWrite Thing '{}' processes a GroupValueWrite telegram for destination '{}' for channel '{}'", - getThing().getUID(), destination, knxChannel.getChannelUID()); - /** - * Remember current KNXIO outboundSpec only if it is a control channel. - */ - if (knxChannel.isControl()) { - logger.trace("onGroupWrite isControl"); - Type value = ValueDecoder.decode(listenSpec.getDPT(), asdu, knxChannel.preferredType()); - if (value != null) { - OutboundSpec commandSpec = knxChannel.getCommandSpec(value); - if (commandSpec != null) { - groupAddressesRespondingSpec.put(destination, commandSpec); - } - } - } - processDataReceived(destination, asdu, listenSpec, knxChannel); - } - } - } - - private void processDataReceived(GroupAddress destination, byte[] asdu, InboundSpec listenSpec, - KNXChannel knxChannel) { - if (DPTUtil.getAllowedTypes(listenSpec.getDPT()).isEmpty()) { - logger.warn("DPT '{}' is not supported by the KNX binding.", listenSpec.getDPT()); - return; - } - - Type value = ValueDecoder.decode(listenSpec.getDPT(), asdu, knxChannel.preferredType()); - if (value != null) { - if (knxChannel.isControl()) { - ChannelUID channelUID = knxChannel.getChannelUID(); - int frequency; - if (KNXBindingConstants.CHANNEL_DIMMER_CONTROL.equals(knxChannel.getChannelType())) { - // if we have a dimmer control channel, check if a frequency is defined - Channel channel = getThing().getChannel(channelUID); - if (channel == null) { - logger.warn("Failed to find channel for ChannelUID '{}'", channelUID); - return; - } - frequency = ((BigDecimal) Objects.requireNonNullElse( - channel.getConfiguration().get(KNXBindingConstants.REPEAT_FREQUENCY), BigDecimal.ZERO)) - .intValue(); - } else { - // disable dimming by binding - frequency = 0; - } - if ((value instanceof UnDefType || value instanceof IncreaseDecreaseType) && frequency > 0) { - // continuous dimming by the binding - // cancel a running scheduler before adding a new (and only add if not UnDefType) - ScheduledFuture oldFuture = channelFutures.remove(channelUID); - if (oldFuture != null) { - oldFuture.cancel(true); - } - if (value instanceof IncreaseDecreaseType) { - channelFutures.put(channelUID, scheduler.scheduleWithFixedDelay( - () -> postCommand(channelUID, (Command) value), 0, frequency, TimeUnit.MILLISECONDS)); - } - } else { - if (value instanceof Command) { - logger.trace("processDataReceived postCommand new value '{}' for GA '{}'", asdu, address); - postCommand(channelUID, (Command) value); - } - } - } else { - if (value instanceof State && !(value instanceof UnDefType)) { - updateState(knxChannel.getChannelUID(), (State) value); - } - } - } else { - logger.debug( - "Ignoring KNX bus data for channel '{}': couldn't transform to any Type (GA='{}', DPT='{}', data='{}')", - knxChannel.getChannelUID(), destination, listenSpec.getDPT(), HexUtils.bytesToHex(asdu)); - } - } - - protected final ScheduledExecutorService getScheduler() { - return getBridgeHandler().getScheduler(); - } - - protected final ScheduledExecutorService getBackgroundScheduler() { - return getBridgeHandler().getBackgroundScheduler(); - } - - protected final KNXBridgeBaseThingHandler getBridgeHandler() { - Bridge bridge = getBridge(); - if (bridge != null) { - KNXBridgeBaseThingHandler handler = (KNXBridgeBaseThingHandler) bridge.getHandler(); - if (handler != null) { - return handler; - } - } - throw new IllegalStateException("The bridge must not be null and must be initialized"); - } - - protected final KNXClient getClient() { - return getBridgeHandler().getClient(); - } - - protected final boolean describeDevice(@Nullable IndividualAddress address) { - if (address == null) { - return false; - } - DeviceInspector inspector = new DeviceInspector(getClient().getDeviceInfoClient(), address); - DeviceInspector.Result result = inspector.readDeviceInfo(); - if (result != null) { - Map properties = editProperties(); - properties.putAll(result.getProperties()); - updateProperties(properties); - return true; - } - return false; - } - - protected final void restart() { - if (address != null) { - getClient().restartNetworkDevice(address); - } - } - - @Override - public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { - if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) { - attachToClient(); - } else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) { - detachFromClient(); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); - } - } - - private void pollDeviceStatus() { - try { - if (address != null && getClient().isConnected()) { - logger.debug("Polling individual address '{}'", address); - boolean isReachable = getClient().isReachable(address); - if (isReachable) { - updateStatus(ThingStatus.ONLINE); - DeviceConfig config = getConfigAs(DeviceConfig.class); - if (!filledDescription && config.getFetch()) { - Future descriptionJob = this.descriptionJob; - if (descriptionJob == null || descriptionJob.isCancelled()) { - long initialDelay = Math.round(config.getPingInterval() * random.nextFloat()); - this.descriptionJob = getBackgroundScheduler().schedule(() -> { - filledDescription = describeDevice(address); - }, initialDelay, TimeUnit.SECONDS); - } - } - } else { - updateStatus(ThingStatus.OFFLINE); - } - } - } catch (KNXException e) { - logger.debug("An error occurred while testing the reachability of a thing '{}'", getThing().getUID(), e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getLocalizedMessage()); - } - } - - protected void attachToClient() { - if (!getClient().isConnected()) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); - return; - } - DeviceConfig config = getConfigAs(DeviceConfig.class); - try { - String configAddress = config.getAddress(); - if (configAddress != null && !configAddress.isEmpty()) { - updateStatus(ThingStatus.UNKNOWN); - address = new IndividualAddress(config.getAddress()); - - long pingInterval = config.getPingInterval(); - long initialPingDelay = Math.round(INITIAL_PING_DELAY * random.nextFloat()); - - ScheduledFuture pollingJob = this.pollingJob; - if ((pollingJob == null || pollingJob.isCancelled())) { - logger.debug("'{}' will be polled every {}s", getThing().getUID(), pingInterval); - this.pollingJob = getBackgroundScheduler().scheduleWithFixedDelay(this::pollDeviceStatus, - initialPingDelay, pingInterval, TimeUnit.SECONDS); - } - } else { - updateStatus(ThingStatus.ONLINE); - } - } catch (KNXFormatException e) { - logger.debug("An exception occurred while setting the individual address '{}'", config.getAddress(), e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getLocalizedMessage()); - } - getClient().registerGroupAddressListener(this); - scheduleReadJobs(); - } - - protected void detachFromClient() { - ScheduledFuture pollingJob = this.pollingJob; - if (pollingJob != null) { - pollingJob.cancel(true); - this.pollingJob = null; - } - - ScheduledFuture descriptionJob = this.descriptionJob; - if (descriptionJob != null) { - descriptionJob.cancel(true); - this.descriptionJob = null; - } - cancelReadFutures(); - Bridge bridge = getBridge(); - if (bridge != null) { - KNXBridgeBaseThingHandler handler = (KNXBridgeBaseThingHandler) bridge.getHandler(); - if (handler != null) { - handler.getClient().unregisterGroupAddressListener(this); - } - } - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/GroupAddressListener.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/GroupAddressListener.java deleted file mode 100644 index f18739b647..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/GroupAddressListener.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.smarthomej.binding.knx.internal.client.BusMessageListener; - -import tuwien.auto.calimero.GroupAddress; - -/** - * The {@link GroupAddressListener} is an interface that needs to be - * implemented by classes that want to listen to Group Addresses - * on the KNX bus - * - * @author Karel Goderis - Initial contribution - */ -@NonNullByDefault -public interface GroupAddressListener extends BusMessageListener { - - /** - * Called to verify if the GroupAddressListener has an interest in the given GroupAddress - * - * @param destination - */ - public boolean listensTo(GroupAddress destination); -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/IPBridgeThingHandler.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/IPBridgeThingHandler.java deleted file mode 100644 index c3ad358d73..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/IPBridgeThingHandler.java +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import java.net.InetSocketAddress; -import java.text.MessageFormat; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.net.NetworkAddressService; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.smarthomej.binding.knx.internal.KNXBindingConstants; -import org.smarthomej.binding.knx.internal.client.CustomKNXNetworkLinkIP; -import org.smarthomej.binding.knx.internal.client.IPClient; -import org.smarthomej.binding.knx.internal.client.KNXClient; -import org.smarthomej.binding.knx.internal.client.NoOpClient; -import org.smarthomej.binding.knx.internal.config.IPBridgeConfiguration; - -/** - * The {@link IPBridgeThingHandler} is responsible for handling commands, which are - * sent to one of the channels. It implements a KNX/IP Gateway, that either acts as a - * conduit for other {@link DeviceThingHandler}s, or for Channels that are - * directly defined on the bridge - * - * @author Karel Goderis - Initial contribution - * @author Simon Kaufmann - Refactoring & cleanup - */ -@NonNullByDefault -public class IPBridgeThingHandler extends KNXBridgeBaseThingHandler { - private static final String MODE_ROUTER = "ROUTER"; - private static final String MODE_TUNNEL = "TUNNEL"; - - private final Logger logger = LoggerFactory.getLogger(IPBridgeThingHandler.class); - - private @Nullable IPClient client; - private final NetworkAddressService networkAddressService; - - public IPBridgeThingHandler(Bridge bridge, NetworkAddressService networkAddressService) { - super(bridge); - this.networkAddressService = networkAddressService; - } - - @Override - public void initialize() { - IPBridgeConfiguration config = getConfigAs(IPBridgeConfiguration.class); - int autoReconnectPeriod = config.getAutoReconnectPeriod(); - if (autoReconnectPeriod != 0 && autoReconnectPeriod < 30) { - logger.info("autoReconnectPeriod for {} set to {}s, allowed range is 0 (never) or >30", thing.getUID(), - autoReconnectPeriod); - autoReconnectPeriod = 30; - config.setAutoReconnectPeriod(autoReconnectPeriod); - } - String localSource = config.getLocalSourceAddr(); - String connectionTypeString = config.getType(); - int port = config.getPortNumber(); - String ip = config.getIpAddress(); - InetSocketAddress localEndPoint = null; - boolean useNAT = false; - int ipConnectionType; - if (MODE_TUNNEL.equalsIgnoreCase(connectionTypeString)) { - useNAT = config.getUseNAT(); - ipConnectionType = CustomKNXNetworkLinkIP.TUNNELING; - } else if (MODE_ROUTER.equalsIgnoreCase(connectionTypeString)) { - if (ip == null || ip.isEmpty()) { - ip = KNXBindingConstants.DEFAULT_MULTICAST_IP; - } - ipConnectionType = CustomKNXNetworkLinkIP.ROUTING; - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - MessageFormat.format("Unknown IP connection type {0}. Known types are either 'TUNNEL' or 'ROUTER'", - connectionTypeString)); - return; - } - if (ip == null) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "The 'ipAddress' of the gateway must be configured in 'TUNNEL' mode"); - return; - } - - String localIp = config.getLocalIp(); - if (localIp != null && !localIp.isEmpty()) { - localEndPoint = new InetSocketAddress(localIp, 0); - } else { - localEndPoint = new InetSocketAddress(networkAddressService.getPrimaryIpv4HostAddress(), 0); - } - - updateStatus(ThingStatus.UNKNOWN); - IPClient client = new IPClient(ipConnectionType, ip, localSource, port, localEndPoint, useNAT, - autoReconnectPeriod, thing.getUID(), config.getResponseTimeout(), config.getReadingPause(), - config.getReadRetriesLimit(), getScheduler(), this); - client.initialize(); - - this.client = client; - } - - @Override - public void dispose() { - super.dispose(); - IPClient client = this.client; - if (client != null) { - client.dispose(); - this.client = null; - } - } - - @Override - protected KNXClient getClient() { - KNXClient ret = client; - if (ret == null) { - return new NoOpClient(); - } - return ret; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/KNXBridgeBaseThingHandler.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/KNXBridgeBaseThingHandler.java deleted file mode 100644 index 531d808974..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/KNXBridgeBaseThingHandler.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.common.ThreadPoolManager; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.openhab.core.thing.binding.BaseBridgeHandler; -import org.openhab.core.types.Command; -import org.smarthomej.binding.knx.internal.client.KNXClient; -import org.smarthomej.binding.knx.internal.client.StatusUpdateCallback; - -import tuwien.auto.calimero.IndividualAddress; -import tuwien.auto.calimero.mgmt.Destination; - -/** - * The {@link KNXBridgeBaseThingHandler} is responsible for handling commands, which are - * sent to one of the channels. - * - * @author Simon Kaufmann - Initial contribution and API - */ -@NonNullByDefault -public abstract class KNXBridgeBaseThingHandler extends BaseBridgeHandler implements StatusUpdateCallback { - - protected ConcurrentHashMap destinations = new ConcurrentHashMap<>(); - private final ScheduledExecutorService knxScheduler = ThreadPoolManager.getScheduledPool("knx"); - private final ScheduledExecutorService backgroundScheduler = Executors.newSingleThreadScheduledExecutor(); - - public KNXBridgeBaseThingHandler(Bridge bridge) { - super(bridge); - } - - protected abstract KNXClient getClient(); - - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - // Nothing to do here - } - - public ScheduledExecutorService getScheduler() { - return knxScheduler; - } - - public ScheduledExecutorService getBackgroundScheduler() { - return backgroundScheduler; - } - - @Override - public void updateStatus(ThingStatus status) { - super.updateStatus(status); - } - - @Override - public void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) { - super.updateStatus(status, statusDetail, description); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/SerialBridgeThingHandler.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/SerialBridgeThingHandler.java deleted file mode 100644 index 686322cbdf..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/handler/SerialBridgeThingHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.handler; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.smarthomej.binding.knx.internal.client.KNXClient; -import org.smarthomej.binding.knx.internal.client.NoOpClient; -import org.smarthomej.binding.knx.internal.client.SerialClient; -import org.smarthomej.binding.knx.internal.config.SerialBridgeConfiguration; - -/** - * The {@link IPBridgeThingHandler} is responsible for handling commands, which are - * sent to one of the channels. It implements a KNX Serial/USB Gateway, that either acts a a - * conduit for other {@link DeviceThingHandler}s, or for Channels that are - * directly defined on the bridge - * - * @author Karel Goderis - Initial contribution - * @author Simon Kaufmann - Refactoring & cleanup - */ -@NonNullByDefault -public class SerialBridgeThingHandler extends KNXBridgeBaseThingHandler { - - private @Nullable SerialClient client; - - public SerialBridgeThingHandler(Bridge bridge) { - super(bridge); - } - - @Override - public void initialize() { - SerialBridgeConfiguration config = getConfigAs(SerialBridgeConfiguration.class); - String serialPort = config.serialPort; - if (serialPort == null || serialPort.isEmpty()) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "serial port not configured"); - return; - } - SerialClient client = new SerialClient(config.getAutoReconnectPeriod(), thing.getUID(), - config.getResponseTimeout(), config.getReadingPause(), config.getReadRetriesLimit(), getScheduler(), - serialPort, config.useCEMI, this); - updateStatus(ThingStatus.UNKNOWN); - client.initialize(); - this.client = client; - } - - @Override - public void dispose() { - super.dispose(); - SerialClient client = this.client; - if (client != null) { - client.dispose(); - } - } - - @Override - protected KNXClient getClient() { - KNXClient ret = client; - if (ret == null) { - return new NoOpClient(); - } - return ret; - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/profiles/KNXProfileAdvisor.java b/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/profiles/KNXProfileAdvisor.java deleted file mode 100644 index 65677190da..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/java/org/smarthomej/binding/knx/internal/profiles/KNXProfileAdvisor.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.profiles; - -import static org.smarthomej.binding.knx.internal.KNXBindingConstants.*; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.thing.Channel; -import org.openhab.core.thing.profiles.ProfileAdvisor; -import org.openhab.core.thing.profiles.ProfileTypeUID; -import org.openhab.core.thing.profiles.SystemProfiles; -import org.openhab.core.thing.type.ChannelType; -import org.openhab.core.thing.type.ChannelTypeUID; -import org.osgi.service.component.annotations.Component; - -/** - * Advisor, provider and factory for the specialized KNX profiles. - * - * @author Simon Kaufmann - initial contribution and API. - * - */ -@Component -@NonNullByDefault -public class KNXProfileAdvisor implements ProfileAdvisor { - - @Override - public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(Channel channel, @Nullable String itemType) { - ChannelTypeUID channelTypeUID = channel.getChannelTypeUID(); - if (channelTypeUID == null || !channelTypeUID.getBindingId().equals(BINDING_ID)) { - return null; - } - return getSuggestedProfieTypeUID(channelTypeUID); - } - - @Override - public @Nullable ProfileTypeUID getSuggestedProfileTypeUID(ChannelType channelType, @Nullable String itemType) { - return getSuggestedProfieTypeUID(channelType.getUID()); - } - - private ProfileTypeUID getSuggestedProfieTypeUID(ChannelTypeUID channelTypeUID) { - if (isControl(channelTypeUID)) { - return SystemProfiles.FOLLOW; - } else { - return SystemProfiles.DEFAULT; - } - } - - public static boolean isControl(ChannelTypeUID channelTypeUID) { - return CONTROL_CHANNEL_TYPES.contains(channelTypeUID.getId()); - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/addon/addon.xml deleted file mode 100644 index f17ae176f4..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/addon/addon.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - knx - KNX Binding - This binding supports connecting to a KNX bus - - - - false - - This disables Units of Measurement support for incoming values. - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/config/channelConfig.xml b/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/config/channelConfig.xml deleted file mode 100644 index 22a1517a0d..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/config/channelConfig.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - The group address (GA) to toggle the dimmer on or off. Additional listening (status) GAs can be added by - concatenating GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first GA, - separated by ":" (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus on - startup. - - - - - The group address to set the absolute brightness (see format description above). - - - - The group address to increase or decrease the dimmer (see format description above). - - - - - - The group address (GA) to toggle the dimmer on or off. Additional listening (status) GAs can be added by - concatenating GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first GA, - separated by ":" (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus on - startup. - - - - - The group address to set the brightness (see format description above). - - - - The group address to increase or decrease the dimmer (see format description above). - - - - Increase/decrease send frequency if dimming should be handled by the binding (in ms) - set to 0 if the - KNX device sends them repeatedly itself. - - 0 - - - - - - - - The group address (GA) to set the color value. Additional listening (status) GAs can be added by - concatenating GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first GA, - separated by ":" (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus on - startup. - - - - - The group address to toggle the color on or off (see format description above). - - - - The group address to set the absolute brightness (see format description above). - - - - The group address to increase or decrease the brightness (see format description above). - - - - - - The group address (GA) to set the color value. Additional listening (status) GAs can be added by - concatenating GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first GA, - separated by ":" (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus on - startup. - - - - - The group address to toggle the color on or off (see format description above). - - - - The group address to set the absolute brightness (see format description above). - - - - The group address to increase or decrease the brightness (see format description above). - - - - Increase/decrease send frequency if color should be handled by the binding (in ms) - set to 0 if the KNX - device sends them repeatedly itself. - 0 - - - - - - - - The group address (GA) to set the moving direction (up/down). Additional listening (status) GAs can be - added by concatenating GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first - GA, separated by ":" (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus - on startup. - - - - - The group address to start (MOVE) or STOP shutter movement (see format description above). - - - - The group address to set the absolute position of the shutter, in % (see format description above). - - - - - - - - The group address (GA) for this channel. Additional listening (status) GAs can be added by concatenating - GAs with a "+" (e.g. "1/7/18+2/9/15"). The DPT can be defined by prepending it to the first GA, separated by ":" - (e.g. "2.001:1/4/17"). GAs prepended with a "<" (e.g. "<5/1/125") are read from the bus on startup. - - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/device.xml b/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/device.xml deleted file mode 100644 index 155185a285..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/device.xml +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - An addressable basic KNX device - - - - - The individual address in x.y.z notation - - - - Read out the device parameters and address/communication object tables - false - - - - Interval (in seconds) between attempts to poll the device status - 600 - - - - Interval (in seconds) between attempts to read the status group addresses on the bus - 0 - - - - - - - Switch - - A channel to manage a generic Group Addresses with a DPT compatible with Switch Items - - - - Switch - - Control a switch item via KNX (i.e. the status is not owned by KNX) - - - - - - Dimmer - - A channel to control a dimmer - - - - Dimmer - - Control a dimmer item via KNX (i.e. the status is not owned by KNX) - - - - - - Rollershutter - - A channel to control a rollershutter - - - - Rollershutter - - Control a rollershutter item (i.e. the status is not owned by KNX) - - - - - - Color - - A channel to control color information (RGB) - - - - Color - - Control a color item (i.e. the status is not owned by KNX) - - - - - - Contact - - A channel to manage a generic Group Addresses with a DPT compatible with Contact Items - - - - Contact - - Control a contact item (i.e. the status is not owned by KNX) - - - - - - Number - - A channel to manage a generic Group Addresses with a DPT compatible with Number Items - - - - Number - - Control a number item (i.e. the status is not owned by KNX) - - - - - - String - - A channel to manage a generic Group Addresses with a DPT compatible with String Items - - - - String - - Control a string item (i.e. the status is not owned by KNX) - - - - - - DateTime - - A channel to manage a generic Group Addresses with a DPT compatible with DateTime Items - - - - DateTime Control - - Control a date/time item (i.e. the status is not owned by KNX) - - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/ip.xml b/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/ip.xml deleted file mode 100644 index 1fb5b39160..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/ip.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - This is a KNX IP interface or router - - - - - The ip connection type for connecting to the KNX bus. Could be either TUNNEL or ROUTER - - - - - true - - - - Network address of the KNX/IP gateway - network-address - - - Port number of the KNX/IP gateway - - 3671 - - - - Network address of the local host to be used to set up the connection to the KNX/IP gateway - network-address - - - - The Physical Address (Individual Address) in x.y.z notation for identification of this KNX/IP gateway - within the KNX bus - 0.0.0 - - - - Set to "true" when having network address translation between this server and the gateway - false - - - - Time in milliseconds of how long should be paused between two read requests to the bus during - initialization - 50 - - - - Seconds to wait for a response from the KNX bus - 10 - - - - Limits the read retries while initialization from the KNX bus - 3 - - - - Seconds between connection retries when KNX link has been lost, 0 means never retry, minimum 30s - 60 - - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/serial.xml b/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/serial.xml deleted file mode 100644 index 41b4477250..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/OH-INF/thing/serial.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - This is a serial interface for accessing the KNX bus - - - serial-port - - The serial port to use for connecting to the KNX bus - - - - Set to "true" when having a ft1.2 serial device that uses CEMI (such as the kBerry) - false - - - - Time in milliseconds of how long should be paused between two read requests to the bus during - initialization - 50 - - - - Seconds to wait for a response from the KNX bus - 10 - - - - Limits the read retries while initialization from the KNX bus - 3 - - - - Seconds between connect retries when KNX link has been lost, 0 means never retry - 0 - - - - - diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/firmware.properties b/bundles/org.smarthomej.binding.knx/src/main/resources/firmware.properties deleted file mode 100644 index b54cef5add..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/firmware.properties +++ /dev/null @@ -1,6 +0,0 @@ -0 = BCU 1, BCU 2, BIM M113 -1 = Unidirectional devices -3 = Property based device management -7 = BIM M112 -8 = IR Decoder, TP1 legacy -9 = Repeater, Coupler diff --git a/bundles/org.smarthomej.binding.knx/src/main/resources/manufacturer.properties b/bundles/org.smarthomej.binding.knx/src/main/resources/manufacturer.properties deleted file mode 100644 index 8b49d57796..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/main/resources/manufacturer.properties +++ /dev/null @@ -1,301 +0,0 @@ -1 = Siemens -2 = ABB -4 = Albrecht Jung -5 = Bticino -6 = Berker -7 = Busch-Jaeger Elektro -8 = GIRA Giersiepen -9 = Hager Electro -10 = INSTA ELEKTRO -11 = LEGRAND Appareillage électrique -12 = Merten -14 = ABB SpA – SACE Division -22 = Siedle & Söhne -24 = Eberle -25 = GEWISS -27 = Albert Ackermann -28 = Schupa GmbH -29 = ABB SCHWEIZ -30 = Feller -32 = DEHN & SÖHNE -33 = CRABTREE -36 = Paul Hochköpper -37 = Altenburger Electronic -41 = Grässlin -42 = Simon -44 = VIMAR -45 = Moeller Gebäudeautomation KG -46 = Eltako -49 = Bosch-Siemens Haushaltsgeräte -52 = RITTO GmbH&Co.KG -53 = Power Controls -55 = ZUMTOBEL -57 = Phoenix Contact -61 = WAGO Kontakttechnik -66 = Wieland Electric -67 = Hermann Kleinhuis -69 = Stiebel Eltron -71 = Tehalit -72 = Theben AG -73 = Wilhelm Rutenbeck -75 = Winkhaus -76 = Robert Bosch -78 = Somfy -80 = Woertz -81 = Viessmann Werke -82 = Theodor HEIMEIER Metallwerk -83 = Joh. Vaillant -85 = AMP Deutschland -89 = Bosch Thermotechnik GmbH -90 = SEF - ECOTEC -92 = DORMA GmbH + Co. KG -93 = WindowMaster A/S -94 = Walther Werke -95 = ORAS -97 = Dätwyler -98 = Electrak -99 = Techem -100 = Schneider Electric Industries SAS -101 = WHD Wilhelm Huber + Söhne -102 = Bischoff Elektronik -104 = JEPAZ -105 = RTS Automation -106 = EIBMARKT GmbH -107 = WAREMA electronic GmbH -108 = Eelectron -109 = Belden Wire & Cable B.V. -110 = Becker-Antriebe GmbH -111 = J.Stehle+Söhne GmbH -112 = AGFEO -113 = Zennio -114 = TAPKO Technologies -115 = HDL -116 = Uponor -117 = se Lightmanagement AG -118 = Arcus-eds -119 = Intesis -120 = Herholdt Controls srl -121 = Zublin AG -122 = Durable Technologies -123 = Innoteam -124 = ise GmbH -125 = TEAM FOR TRONICS -126 = CIAT -127 = Remeha BV -128 = ESYLUX -129 = BASALTE -130 = Vestamatic -131 = MDT technologies -132 = Warendorfer Küchen GmbH -133 = Video-Star -134 = Sitek -135 = CONTROLtronic -136 = function Technology -137 = AMX -138 = ELDAT -139 = VIKO -140 = Pulse Technologies -141 = Crestron -142 = STEINEL professional -143 = BILTON LED Lighting -144 = denro AG -145 = GePro -146 = preussen automation -147 = Zoppas Industries -148 = MACTECH -149 = TECHNO-TREND -150 = FS Cables -151 = Delta Dore -152 = Eissound -153 = Cisco -154 = Dinuy -155 = iKNiX -156 = Rademacher Geräte-Elektronik GmbH & Co. KG -157 = EGi Electroacustica General Iberica -158 = Ingenium -159 = ElabNET -160 = Blumotix -161 = Hunter Douglas -162 = APRICUM -163 = TIANSU Automation -164 = Bubendorff -165 = MBS GmbH -166 = Enertex Bayern GmbH -167 = BMS -168 = Sinapsi -169 = Embedded Systems SIA -170 = KNX1 -171 = Tokka -172 = NanoSense -173 = PEAR Automation GmbH -174 = DGA -175 = Lutron -176 = AIRZONE – ALTRA -177 = Lithoss Design Switches -178 = 3ATEL -179 = Philips Controls -180 = VELUX A/S -181 = LOYTEC -182 = SBS S.p.A. -183 = SIRLAN Technologies -184 = Bleu Comm' Azur -185 = IT GmbH -186 = RENSON -187 = HEP Group -188 = Balmart -189 = GFS GmbH -190 = Schenker Storen AG -191 = Algodue Elettronica S.r.L. -192 = Newron System -193 = maintronic -194 = Vantage -195 = Foresis -196 = Research & Production Association SEM -197 = Weinzierl Engineering GmbH -198 = Möhlenhoff Wärmetechnik GmbH -199 = PKC-GROUP Oyj -200 = B.E.G. -201 = Elsner Elektronik GmbH -202 = Siemens Building Technologies (HK/China) Ltd. -204 = Eutrac -205 = Gustav Hensel GmbH & Co. KG -206 = GARO AB -207 = Waldmann Lichttechnik -208 = SCHÜCO -209 = EMU -210 = JNet Systems AG -214 = O.Y.L. Electronics -215 = Galax System -216 = Disch -217 = Aucoteam -218 = Luxmate Controls -219 = Danfoss -220 = AST GmbH -222 = WILA Leuchten -223 = b+b Automations- und Steuerungstechnik -225 = Lingg & Janke -227 = Sauter -228 = SIMU -232 = Theben HTS AG -233 = Amann GmbH -234 = BERG Energiekontrollsysteme GmbH -235 = Hüppe Form Sonnenschutzsysteme GmbH -237 = Oventrop KG -238 = Griesser AG -239 = IPAS GmbH -240 = elero GmbH -241 = Ardan Production and Industrial Controls Ltd. -242 = Metec Meßtechnik GmbH -244 = ELKA-Elektronik GmbH -245 = ELEKTROANLAGEN D. NAGEL -246 = Tridonic Bauelemente GmbH -248 = Stengler Gesellschaft -249 = Schneider Electric (MG) -250 = KNX Association -251 = VIVO -252 = Hugo Müller GmbH & Co KG -253 = Siemens HVAC -254 = APT -256 = HighDom -257 = Top Services -258 = ambiHome -259 = DATEC electronic AG -260 = ABUS Security-Center -261 = Lite-Puter -262 = Tantron Electronic -263 = Yönnet -264 = DKX Tech -265 = Viatron -266 = Nautibus -268 = Longchuang -269 = Air-On AG -270 = ib-company GmbH -271 = SATION -272 = Agentilo GmbH -273 = Makel Elektrik -274 = Helios Ventilatoren -275 = Otto Solutions Pte Ltd -276 = Airmaster -277 = HEINEMANN GmbH -278 = LDS -279 = ASIN -280 = Bridges -281 = ARBONIA -282 = KERMI -283 = PROLUX -284 = ClicHome -285 = COMMAX -286 = EAE -287 = Tense -288 = Seyoung Electronics -289 = Lifedomus -290 = EUROtronic Technology GmbH -291 = tci -292 = Rishun Electronic -293 = Zipato -294 = cm-security GmbH & Co KG -295 = Qing Cables -296 = LABIO -297 = Coster Tecnologie Elettroniche S.p.A. -298 = E.G.E -299 = NETxAutomation -300 = tecalor -301 = Urmet Electronics (Huizhou) Ltd. -302 = Peiying Building Control -303 = BPT S.p.A. a Socio Unico -304 = Kanontec - KanonBUS -305 = ISER Tech -306 = Fineline -307 = CP Electronics Ltd -308 = Servodan A/S -309 = Simon -310 = GM modular pvt. Ltd. -311 = FU CHENG Intelligence -312 = NexKon -313 = FEEL s.r.l -314 = Not Assigned -315 = Shenzhen Fanhai Sanjiang Electronics Co., Ltd. -316 = Jiuzhou Greeble -317 = Aumüller Aumatic GmbH -318 = Etman Electric -319 = EMT Controls -320 = ZidaTech AG -321 = IDGS bvba -322 = dakanimo -323 = Trebor Automation AB -324 = Satel sp. z o.o. -325 = Russound, Inc. -326 = Midea Heating & Ventilating Equipment CO LTD -327 = Consorzio Terranuova -328 = Wolf Heiztechnik GmbH -329 = SONTEC -330 = Belcom Cables Ltd. -331 = Guangzhou SeaWin Electrical Technologies Co., Ltd. -332 = Acrel -333 = Franke Aquarotter GmbH -334 = Orion Systems -335 = Schrack Technik GmbH -336 = INSPRID -337 = Sunricher -338 = Menred automation system(shanghai) Co.,Ltd. -339 = Aurex -340 = Josef Barthelme GmbH & Co. KG -341 = Architecture Numerique -342 = UP GROUP -343 = Teknos-Avinno -344 = Ningbo Dooya Mechanic & Electronic Technology -345 = Thermokon Sensortechnik GmbH -346 = BELIMO Automation AG -347 = Zehnder Group International AG -348 = sks Kinkel Elektronik -349 = ECE Wurmitzer GmbH -350 = LARS -351 = URC -352 = LightControl -353 = ShenZhen YM -354 = MEAN WELL Enterprises Co. Ltd. -355 = OSix -356 = AYPRO Technology -357 = Hefei Ecolite Software -358 = Enno -359 = Ohosure diff --git a/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/channel/KNXChannelTest.java b/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/channel/KNXChannelTest.java deleted file mode 100644 index 029d694460..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/channel/KNXChannelTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.channel; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.jupiter.api.Test; -import org.openhab.core.config.core.Configuration; -import org.openhab.core.thing.Channel; -import org.openhab.core.thing.type.ChannelTypeUID; -import org.openhab.core.types.UnDefType; - -import tuwien.auto.calimero.GroupAddress; -import tuwien.auto.calimero.KNXFormatException; - -/** - * - * @author Simon Kaufmann - Initial contribution - * - */ -@NonNullByDefault -public class KNXChannelTest { - - @Test - public void invalidFails() { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<1/3/22+0/3/22+<0/8/15"); - assertNull(res); - } - - @Test - public void testParseWithDPTMultipleWithRead() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<1/3/22+0/3/22+<0/7/15"); - - if (res == null) { - fail(); - return; - } - - assertEquals("5.001", res.getDPT()); - assertEquals(new GroupAddress("1/3/22"), res.getMainGA()); - assertTrue(res.getReadGAs().contains(res.getMainGA())); - assertEquals(3, res.getListenGAs().size()); - assertEquals(2, res.getReadGAs().size()); - } - - @Test - public void testParseWithDPTMultipleWithoutRead() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:1/3/22+0/3/22+0/7/15"); - - if (res == null) { - fail(); - return; - } - - assertEquals("5.001", res.getDPT()); - assertEquals(new GroupAddress("1/3/22"), res.getMainGA()); - assertFalse(res.getReadGAs().contains(res.getMainGA())); - assertEquals(3, res.getListenGAs().size()); - assertEquals(0, res.getReadGAs().size()); - } - - @Test - public void testParseWithoutDPTSingleWithoutRead() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("1/3/22"); - - if (res == null) { - fail(); - return; - } - - assertNull(res.getDPT()); - assertEquals(new GroupAddress("1/3/22"), res.getMainGA()); - assertFalse(res.getReadGAs().contains(res.getMainGA())); - assertEquals(1, res.getListenGAs().size()); - assertEquals(0, res.getReadGAs().size()); - } - - @Test - public void testParseWithoutDPTSingleWithRead() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("<1/3/22"); - - if (res == null) { - fail(); - return; - } - - assertNull(res.getDPT()); - assertEquals(new GroupAddress("1/3/22"), res.getMainGA()); - assertTrue(res.getReadGAs().contains(res.getMainGA())); - assertEquals(1, res.getListenGAs().size()); - assertEquals(1, res.getReadGAs().size()); - } - - @Test - public void testParseTwoLevel() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<3/1024+<4/1025"); - - if (res == null) { - fail(); - return; - } - - assertEquals(new GroupAddress("3/1024"), res.getMainGA()); - assertTrue(res.getReadGAs().contains(res.getMainGA())); - assertEquals(2, res.getListenGAs().size()); - assertEquals(2, res.getReadGAs().size()); - } - - @Test - public void testParseFreeLevel() throws KNXFormatException { - GroupAddressConfiguration res = GroupAddressConfiguration.parse("5.001:<4610+<4611"); - - if (res == null) { - fail(); - return; - } - - assertEquals(new GroupAddress("4610"), res.getMainGA()); - assertEquals(2, res.getListenGAs().size()); - assertEquals(2, res.getReadGAs().size()); - } - - @Test - public void testChannelGaParsing() throws KNXFormatException { - Channel channel = mock(Channel.class); - Configuration configuration = new Configuration( - Map.of("key1", "5.001:<1/2/3+4/5/6+1/5/6", "key2", "1.001:7/1/9+1/1/2")); - - when(channel.getChannelTypeUID()).thenReturn(new ChannelTypeUID("a:b:c")); - when(channel.getConfiguration()).thenReturn(configuration); - when(channel.getAcceptedItemType()).thenReturn("none"); - - MyKNXChannel knxChannel = new MyKNXChannel(channel); - - Set listenAddresses = knxChannel.getAllGroupAddresses(); - assertEquals(5, listenAddresses.size()); - // we don't check the content since parsing has been checked before and the quantity is correct - Set writeAddresses = knxChannel.getWriteAddresses(); - assertEquals(2, writeAddresses.size()); - assertTrue(writeAddresses.contains(new GroupAddress("1/2/3"))); - assertTrue(writeAddresses.contains(new GroupAddress("7/1/9"))); - } - - private static class MyKNXChannel extends KNXChannel { - public MyKNXChannel(Channel channel) { - super(Set.of("key1", "key2"), List.of(UnDefType.class), channel); - } - - @Override - protected String getDefaultDPT(String gaConfigKey) { - return ""; - } - } -} diff --git a/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/dpt/DPTTest.java b/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/dpt/DPTTest.java deleted file mode 100644 index 156ce54d72..0000000000 --- a/bundles/org.smarthomej.binding.knx/src/test/java/org/smarthomej/binding/knx/internal/dpt/DPTTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * Copyright (c) 2021-2023 Contributors to the SmartHome/J project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.smarthomej.binding.knx.internal.dpt; - -import static org.junit.jupiter.api.Assertions.*; - -import java.nio.charset.StandardCharsets; -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.QuantityType; - -/** - * - * @author Simon Kaufmann - Initial contribution - * - */ -@NonNullByDefault -public class DPTTest { - - @Test - public void testToDPTValueTrailingZeroesStrippedOff() { - assertEquals("3", ValueEncoder.encode(new DecimalType("3"), "17.001")); - assertEquals("3", ValueEncoder.encode(new DecimalType("3.0"), "17.001")); - } - - @Test - public void testToDPTValueDecimalType() { - assertEquals("23.1", ValueEncoder.encode(new DecimalType("23.1"), "9.001")); - } - - @Test - public void testToDPTValueQuantityType() { - assertEquals("23.1", ValueEncoder.encode(new QuantityType<>("23.1 °C"), "9.001")); - } - - @Test - public void dpt232RgbValue() { - // input data - byte[] data = new byte[] { 123, 45, 67 }; - - // this is the old implementation - String value = "r:123 g:45 b:67"; - int r = Integer.parseInt(value.split(" ")[0].split(":")[1]); - int g = Integer.parseInt(value.split(" ")[1].split(":")[1]); - int b = Integer.parseInt(value.split(" ")[2].split(":")[1]); - HSBType expected = HSBType.fromRGB(r, g, b); - - assertEquals(expected, ValueDecoder.decode("232.600", data, HSBType.class)); - } - - @Test - public void dpt232HsbValue() { - // input data - byte[] data = new byte[] { 123, 45, 67 }; - - HSBType hsbType = (HSBType) ValueDecoder.decode("232.60000", data, HSBType.class); - - Assertions.assertNotNull(hsbType); - assertEquals(173.6, hsbType.getHue().doubleValue(), 0.1); - assertEquals(17.6, hsbType.getSaturation().doubleValue(), 0.1); - assertEquals(26.3, hsbType.getBrightness().doubleValue(), 0.1); - } - - @Test - public void dpt252EncoderTest() { - // input data - byte[] data = new byte[] { 0x26, 0x2b, 0x31, 0x00, 0x00, 0x0e }; - HSBType hsbType = (HSBType) ValueDecoder.decode("251.600", data, HSBType.class); - - assertNotNull(hsbType); - assertEquals(207, hsbType.getHue().doubleValue(), 0.0025 * 360); - assertEquals(23, hsbType.getSaturation().doubleValue(), 0.0025 * 100); - assertEquals(19, hsbType.getBrightness().doubleValue(), 0.0025 * 100); - } - - @SuppressWarnings("unused") - private static Stream unitProvider() { - return DPTUnits.getAllUnitStrings(); - } - - @ParameterizedTest - @MethodSource("unitProvider") - public void unitsValid(String unit) { - String valueStr = "1 " + unit; - QuantityType value = new QuantityType<>(valueStr); - Assertions.assertNotNull(value); - } - - private static Stream rgbValueProvider() { - return Stream.of("r:0 g:0 b:0", "r:255 g:255 b:255"); - } - - @ParameterizedTest - @MethodSource("rgbValueProvider") - public void rgbTest(String value) { - Assertions.assertNotNull(ValueDecoder.decode("232.600", value.getBytes(StandardCharsets.UTF_8), HSBType.class)); - } -} diff --git a/bundles/pom.xml b/bundles/pom.xml index 819348622d..b5cfd5d40b 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -25,7 +25,6 @@ org.smarthomej.binding.androiddebugbridge org.smarthomej.binding.amazonechocontrol org.smarthomej.binding.http - org.smarthomej.binding.knx org.smarthomej.binding.notificationsforfiretv org.smarthomej.binding.tcpudp org.smarthomej.binding.telenot