mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 23:22:02 +01:00
[mikrotik] Mikrotik RouterOS Binding - Initial contribution (#10014)
* [mikrotik] Initial contribution Build fix Linter concerns fixed Post-review updates Apply suggestions from code review Co-authored-by: Matthew Skinner <matt@pcmus.com> [mikrotik] Byte channels UOM update [mikrotik] UOM updates; minor improvements [mikrotik] ThingTypes update Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Version bump, bugfix (thanks @radokristof) Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Raw uptime channel removed Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Traces removed Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Readme update Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] More Null checks Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] thing-types update Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Units update Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Readme signal update Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Rate channels unit fix Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Work on codestyle report and some compiler warnings Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] No more compiler warnings Signed-off-by: Oleg Vivtash <oleg@vivtash.net> * [mikrotik] Minus null check Signed-off-by: Oleg Vivtash <oleg@vivtash.net> Co-authored-by: Fabian Wolter <github@fabian-wolter.de> Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
This commit is contained in:
parent
fd646a59bd
commit
5ae1567ba8
@ -172,6 +172,7 @@
|
|||||||
/bundles/org.openhab.binding.mielecloud/ @BjoernLange
|
/bundles/org.openhab.binding.mielecloud/ @BjoernLange
|
||||||
/bundles/org.openhab.binding.mihome/ @pboos
|
/bundles/org.openhab.binding.mihome/ @pboos
|
||||||
/bundles/org.openhab.binding.miio/ @marcelrv
|
/bundles/org.openhab.binding.miio/ @marcelrv
|
||||||
|
/bundles/org.openhab.binding.mikrotik/ @duhast
|
||||||
/bundles/org.openhab.binding.milight/ @davidgraeff
|
/bundles/org.openhab.binding.milight/ @davidgraeff
|
||||||
/bundles/org.openhab.binding.millheat/ @seime
|
/bundles/org.openhab.binding.millheat/ @seime
|
||||||
/bundles/org.openhab.binding.minecraft/ @ibaton
|
/bundles/org.openhab.binding.minecraft/ @ibaton
|
||||||
|
@ -848,6 +848,11 @@
|
|||||||
<artifactId>org.openhab.binding.miio</artifactId>
|
<artifactId>org.openhab.binding.miio</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.binding.mikrotik</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
<artifactId>org.openhab.binding.milight</artifactId>
|
<artifactId>org.openhab.binding.milight</artifactId>
|
||||||
|
13
bundles/org.openhab.binding.mikrotik/NOTICE
Normal file
13
bundles/org.openhab.binding.mikrotik/NOTICE
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
This content is produced and maintained by the openHAB project.
|
||||||
|
|
||||||
|
* Project home: https://www.openhab.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/openhab/openhab-addons
|
374
bundles/org.openhab.binding.mikrotik/README.md
Normal file
374
bundles/org.openhab.binding.mikrotik/README.md
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
# Mikrotik RouterOS Binding
|
||||||
|
|
||||||
|
This binding integrates [Mikrotik](https://mikrotik.com/) [RouterOS](https://help.mikrotik.com/docs/display/ROS/RouterOS)
|
||||||
|
[devices](https://mikrotik.com/products) allowing monitoring of system resources, network interfaces and WiFi clients.
|
||||||
|
|
||||||
|
## Supported Things
|
||||||
|
|
||||||
|
* `routeros` - An instance of the RouterOS device connection
|
||||||
|
* `interface` - A network interface inside RouterOS device
|
||||||
|
* `wifiRegistration` - Any wireless client connected to a RouterOS wireless network (regular or CAPsMAN-managed)
|
||||||
|
|
||||||
|
|
||||||
|
## Discovery
|
||||||
|
|
||||||
|
Discovery is currently not supported, but may be implemented in future versions.
|
||||||
|
|
||||||
|
|
||||||
|
## Bridge Configuration
|
||||||
|
|
||||||
|
To use this binding you need at least one RouterOS-powered device (Bridge) accessible to the host running
|
||||||
|
openHAB via network.
|
||||||
|
Make sure your RouterOS has the API enabled by visiting [<kbd>IP -> Services</kbd>](https://wiki.mikrotik.com/wiki/Manual:IP/Services)
|
||||||
|
configuration section in
|
||||||
|
[WinBox](https://wiki.mikrotik.com/wiki/Manual:Winbox).
|
||||||
|
Take note of the API port number as you'll need it below.
|
||||||
|
[SSL API connection](https://wiki.mikrotik.com/wiki/Manual:API-SSL) is not yet supported by this binding.
|
||||||
|
To connect to the RouterOS API, you will need to provide user credentials for the bridge thing.
|
||||||
|
You may use your current credentials that you use to manage your devices, but it is highly recommended to **create a read-only RouterOS user** since this binding only need to read data from the device.
|
||||||
|
To do this, proceed to <kbd>System -> Users</kbd> configuration section and add a user to the `read` group.
|
||||||
|
|
||||||
|
> Thing type: `routeros`
|
||||||
|
|
||||||
|
The RouterOS Bridge configuration parameters are:
|
||||||
|
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| host | text | Yes | 192.168.88.1 | Hostname or IP address of the RouterOS device |
|
||||||
|
| port | integer | No | 8728 | API Port number of the RouterOS device |
|
||||||
|
| login | text | Yes | admin | The username to access the the RouterOS device |
|
||||||
|
| password | text | Yes | | The user password to access the RouterOS device |
|
||||||
|
| refresh | integer | No | 10 | The refresh interval in seconds to poll the RouterOS device |
|
||||||
|
|
||||||
|
**All things provided by this binding require a working bridge to be set up.**
|
||||||
|
|
||||||
|
|
||||||
|
### Bridge Channels
|
||||||
|
|
||||||
|
| Channel | Type | Description | Comment |
|
||||||
|
|---|---|---|---|
|
||||||
|
| freeSpace | Number:DataAmount | Amount of free storage left on device in bytes | |
|
||||||
|
| totalSpace | Number:DataAmount | Amount of total storage available on device in bytes | |
|
||||||
|
| usedSpace | Number:Dimensionless | Percentage of used device storage space | |
|
||||||
|
| freeMemory | Number:DataAmount | Amount of free memory left on device in bytes | |
|
||||||
|
| totalMemory | Number:DataAmount | Amount of total memory available on device in bytes | |
|
||||||
|
| usedMemory | Number:Dimensionless | Percentage of used device memory | |
|
||||||
|
| cpuLoad | Number:Dimensionless | CPU load percentage | |
|
||||||
|
| upSince | DateTime | Time when thing got up | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## WiFi Client Thing Configuration
|
||||||
|
|
||||||
|
> Thing type: `wifiRegistration`
|
||||||
|
|
||||||
|
Represents a wireless client connected to a RouterOS wireless network (direct or CAPsMAN-managed).
|
||||||
|
|
||||||
|
The WiFi client thing configuration parameters are:
|
||||||
|
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| mac | text | Yes | | WiFi client MAC address |
|
||||||
|
| ssid | text | No | | Constraining SSID for the WiFi client (optional). If client will connect to another SSID, this thing will stay offline until client reconnects to specified SSID. |
|
||||||
|
| considerContinuous | integer | No | 180 | The interval in seconds to treat the client as connected permanently |
|
||||||
|
|
||||||
|
### WiFi client Thing Channels
|
||||||
|
|
||||||
|
| Channel | Type | Description | Comment |
|
||||||
|
|---|---|---|---|
|
||||||
|
| macAddress | String | MAC address of the client or interface | |
|
||||||
|
| comment | String | User-defined comment | |
|
||||||
|
| connected | Switch | Reflects connected or disconnected state | |
|
||||||
|
| continuous | Switch | Connection is considered long-running | |
|
||||||
|
| ssid | String | Wireless Network (SSID) the wireless client is connected to | |
|
||||||
|
| interface | String | Network interface name | |
|
||||||
|
| signal | system.signal-strength | Signal strength (RSSI) | |
|
||||||
|
| upSince | DateTime | Time when thing got up | |
|
||||||
|
| lastSeen | DateTime | Time of when the client was last seen connected | |
|
||||||
|
| txRate | Number:DataTransferRate | Rate of data transmission in megabits per second | |
|
||||||
|
| rxRate | Number:DataTransferRate | Rate of data receiving in megabits per second | |
|
||||||
|
| txPacketRate | Number | Rate of data transmission in packets per second | |
|
||||||
|
| rxPacketRate | Number | Rate of data receiving in packets per second | |
|
||||||
|
| txBytes | Number:DataAmount | Amount of bytes transmitted | |
|
||||||
|
| rxBytes | Number:DataAmount | Amount of bytes received | |
|
||||||
|
| txPackets | Number | Amount of packets transmitted | |
|
||||||
|
| rxPackets | Number | Amount of packets received | |
|
||||||
|
|
||||||
|
## Network Interface Thing Configuration
|
||||||
|
|
||||||
|
> Thing type: `interface`
|
||||||
|
|
||||||
|
Represents a network interface from RouterOS system (ethernet, wifi, vpn, etc.)
|
||||||
|
At the moment the binding supports the following RouterOS interface types:
|
||||||
|
|
||||||
|
* `ether`
|
||||||
|
* `bridge`
|
||||||
|
* `wlan`
|
||||||
|
* `cap`
|
||||||
|
* `pppoe-out`
|
||||||
|
* `l2tp-in`
|
||||||
|
* `l2tp-out`
|
||||||
|
|
||||||
|
The interface thing configuration parameters are:
|
||||||
|
|
||||||
|
### Interface Thing Configuration
|
||||||
|
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| name | text | Yes | | RouterOS Interface name (i.e. ether1) |
|
||||||
|
|
||||||
|
### Interface Thing Channels
|
||||||
|
|
||||||
|
Please note that different on RouterOS interfaces has different data available depending on the kind of interface.
|
||||||
|
While the common dataset is same, some specific information for specific interface type may be missing. This may
|
||||||
|
be improved in future binding versions.
|
||||||
|
|
||||||
|
Common for all kinds of interfaces:
|
||||||
|
|
||||||
|
| Channel | Type | Description | Comment |
|
||||||
|
|---|---|---|---|
|
||||||
|
| type | String | Network interface type | |
|
||||||
|
| name | String | Network interface name | |
|
||||||
|
| comment | String | User-defined comment | |
|
||||||
|
| macAddress | String | MAC address of the client or interface | |
|
||||||
|
| enabled | Switch | Reflects enabled or disabled state | |
|
||||||
|
| connected | Switch | Reflects connected or disconnected state | |
|
||||||
|
| lastLinkDownTime | DateTime | Last time when link went down | |
|
||||||
|
| lastLinkUpTime | DateTime | Last time when link went up | |
|
||||||
|
| linkDowns | Number | Amount of link downs | |
|
||||||
|
| txRate | Number:DataTransferRate | Rate of data transmission in megabits per second | |
|
||||||
|
| rxRate | Number:DataTransferRate | Rate of data receiving in megabits per second | |
|
||||||
|
| txPacketRate | Number | Rate of data transmission in packets per second | |
|
||||||
|
| rxPacketRate | Number | Rate of data receiving in packets per second | |
|
||||||
|
| txBytes | Number:DataAmount | Amount of bytes transmitted | |
|
||||||
|
| rxBytes | Number:DataAmount | Amount of bytes received | |
|
||||||
|
| txPackets | Number | Amount of packets transmitted | |
|
||||||
|
| rxPackets | Number | Amount of packets received | |
|
||||||
|
| txDrops | Number | Amount of packets dropped during transmission | |
|
||||||
|
| rxDrops | Number | Amount of packets dropped during receiving | |
|
||||||
|
| txErrors | Number | Amount of errors during transmission | |
|
||||||
|
| rxErrors | Number | Amount of errors during receiving | |
|
||||||
|
| defaultName | String | Interface factory name | Populated only for `ether` interfaces |
|
||||||
|
| rate | String | Ethernet link rate | Populated only for `ether` interfaces |
|
||||||
|
| state | String | WiFi interface state | |
|
||||||
|
| registeredClients | Number | Amount of clients registered to WiFi interface | Populated only for `cap` interfaces |
|
||||||
|
| authorizedClients | Number | Amount of clients authorized by WiFi interface | Populated only for `cap` interfaces |
|
||||||
|
| upSince | DateTime | Time when thing got up | Populated only for `cap` interfaces |
|
||||||
|
|
||||||
|
## Text Configuration Example
|
||||||
|
|
||||||
|
**Change config options accordingly.**
|
||||||
|
|
||||||
|
_things/mikrotik.things_
|
||||||
|
|
||||||
|
```
|
||||||
|
Bridge mikrotik:routeros:rb1 "My RouterBoard" [ host="192.168.0.1", port=8728, login="openhab", password="thatsasecret", refresh=10 ] {
|
||||||
|
Thing interface eth1 "Eth1" [ name="ether1" ]
|
||||||
|
Thing interface eth2 "Eth2" [ name="ether2-wan1" ]
|
||||||
|
Thing interface cap1 "Cap1" [ name="cap5" ]
|
||||||
|
Thing interface ppp1 "PPPoE1" [ name="isp-pppoe" ]
|
||||||
|
Thing interface tun1 "L2TPSrv1" [ name="l2tp-parents" ]
|
||||||
|
Thing wifiRegistration wifi1 "Phone1" [ mac="F4:60:E2:C5:47:94", considerContinuous=60 ]
|
||||||
|
Thing wifiRegistration wifi2 "Tablet2" [ mac="18:1D:EA:A5:A2:9E" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
_items/mikrotik.items_
|
||||||
|
|
||||||
|
```
|
||||||
|
Group gRB1 "RB3011 System"
|
||||||
|
Number:DataAmount My_RB_3011_Free_Space "Free space" (gRB1) {channel="mikrotik:routeros:rb1:freeSpace"}
|
||||||
|
Number:DataAmount My_RB_3011_Total_Space "Total space" (gRB1) {channel="mikrotik:routeros:rb1:totalSpace"}
|
||||||
|
Number:Dimensionless My_RB_3011_Used_Space "Used space" (gRB1) {channel="mikrotik:routeros:rb1:usedSpace"}
|
||||||
|
Number:DataAmount My_RB_3011_Free_Memory "Free ram" (gRB1) {channel="mikrotik:routeros:rb1:freeMemory"}
|
||||||
|
Number:DataAmount My_RB_3011_Total_Memory "Total ram" (gRB1) {channel="mikrotik:routeros:rb1:totalMemory"}
|
||||||
|
Number:Dimensionless My_RB_3011_Used_Memory "Used ram" (gRB1) {channel="mikrotik:routeros:rb1:usedMemory"}
|
||||||
|
Number:Dimensionless My_RB_3011_Cpu_Load "Cpu load" (gRB1) {channel="mikrotik:routeros:rb1:cpuLoad"}
|
||||||
|
DateTime My_RB_3011_Upsince "Up since [%1$td.%1$tm.%1$ty %1$tH:%1$tM]" (gRB1) {channel="mikrotik:routeros:rb1:upSince"}
|
||||||
|
|
||||||
|
Group gRB1Eth1 "Ethernet Interface 1"
|
||||||
|
String Eth_1_Type "Type" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:type"}
|
||||||
|
String Eth_1_Name "Name" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:name"}
|
||||||
|
String Eth_1_Comment "Comment" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:comment"}
|
||||||
|
String Eth_1_Mac_Address "Mac address" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:macAddress"}
|
||||||
|
Switch Eth_1_Enabled "Enabled" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:enabled"}
|
||||||
|
Switch Eth_1_Connected "Connected" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:connected"}
|
||||||
|
DateTime Eth_1_Last_Link_Down_Time "Last link down" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:lastLinkDownTime"}
|
||||||
|
DateTime Eth_1_Last_Link_Up_Time "Last link up" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:lastLinkUpTime"}
|
||||||
|
Number Eth_1_Link_Downs "Link downs" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:linkDowns"}
|
||||||
|
Number:DataTransferRate Eth_1_Tx_Rate "Transmission rate" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txRate"}
|
||||||
|
Number:DataTransferRate Eth_1_Rx_Rate "Receiving rate" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxRate"}
|
||||||
|
Number Eth_1_Tx_Packet_Rate "Transmission packet rate" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txPacketRate"}
|
||||||
|
Number Eth_1_Rx_Packet_Rate "Receiving packet rate" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxPacketRate"}
|
||||||
|
Number:DataAmount Eth_1_Tx_Bytes "Transmitted bytes" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txBytes"}
|
||||||
|
Number:DataAmount Eth_1_Rx_Bytes "Received bytes" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxBytes"}
|
||||||
|
Number Eth_1_Tx_Packets "Transmitted packets" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txPackets"}
|
||||||
|
Number Eth_1_Rx_Packets "Received packets" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxPackets"}
|
||||||
|
Number Eth_1_Tx_Drops "Transmission drops" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txDrops"}
|
||||||
|
Number Eth_1_Rx_Drops "Receiving drops" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxDrops"}
|
||||||
|
Number Eth_1_Tx_Errors "Transmission errors" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:txErrors"}
|
||||||
|
Number Eth_1_Rx_Errors "Receiving errors" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rxErrors"}
|
||||||
|
String Eth_1_Default_Name "Default name" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:defaultName"}
|
||||||
|
String Eth_1_Rate "Link rate" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:rate"}
|
||||||
|
String Eth_1_Auto_Negotiation "Auto negotiation" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:autoNegotiation"}
|
||||||
|
String Eth_1_State "State" (gRB1Eth1) {channel="mikrotik:interface:rb1:eth1:state"}
|
||||||
|
|
||||||
|
Group gRB1Eth2 "Ethernet Interface 2"
|
||||||
|
String Eth_2_Type "Type" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:type"}
|
||||||
|
String Eth_2_Name "Name" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:name"}
|
||||||
|
String Eth_2_Comment "Comment" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:comment"}
|
||||||
|
String Eth_2_Mac_Address "Mac address" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:macAddress"}
|
||||||
|
Switch Eth_2_Enabled "Enabled" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:enabled"}
|
||||||
|
Switch Eth_2_Connected "Connected" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:connected"}
|
||||||
|
DateTime Eth_2_Last_Link_Down_Time "Last link down" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:lastLinkDownTime"}
|
||||||
|
DateTime Eth_2_Last_Link_Up_Time "Last link up" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:lastLinkUpTime"}
|
||||||
|
Number Eth_2_Link_Downs "Link downs" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:linkDowns"}
|
||||||
|
Number:DataTransferRate Eth_2_Tx_Rate "Transmission rate" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txRate"}
|
||||||
|
Number:DataTransferRate Eth_2_Rx_Rate "Receiving rate" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxRate"}
|
||||||
|
Number Eth_2_Tx_Packet_Rate "Transmission packet rate" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txPacketRate"}
|
||||||
|
Number Eth_2_Rx_Packet_Rate "Receiving packet rate" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxPacketRate"}
|
||||||
|
Number:DataAmount Eth_2_Tx_Bytes "Transmitted bytes" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txBytes"}
|
||||||
|
Number:DataAmount Eth_2_Rx_Bytes "Received bytes" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxBytes"}
|
||||||
|
Number Eth_2_Tx_Packets "Transmitted packets" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txPackets"}
|
||||||
|
Number Eth_2_Rx_Packets "Received packets" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxPackets"}
|
||||||
|
Number Eth_2_Tx_Drops "Transmission drops" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txDrops"}
|
||||||
|
Number Eth_2_Rx_Drops "Receiving drops" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxDrops"}
|
||||||
|
Number Eth_2_Tx_Errors "Transmission errors" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:txErrors"}
|
||||||
|
Number Eth_2_Rx_Errors "Receiving errors" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rxErrors"}
|
||||||
|
String Eth_2_Default_Name "Default name" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:defaultName"}
|
||||||
|
String Eth_2_Rate "Link rate" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:rate"}
|
||||||
|
String Eth_2_Auto_Negotiation "Auto negotiation" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:autoNegotiation"}
|
||||||
|
String Eth_2_State "State" (gRB1Eth2) {channel="mikrotik:interface:rb1:eth2:state"}
|
||||||
|
|
||||||
|
Group gRB1Cap1 "CAPsMAN Inerface 1"
|
||||||
|
String Cap_1_Type "Type" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:type"}
|
||||||
|
String Cap_1_Name "Name" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:name"}
|
||||||
|
String Cap_1_Comment "Comment" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:comment"}
|
||||||
|
String Cap_1_Mac_Address "Mac address" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:macAddress"}
|
||||||
|
Switch Cap_1_Enabled "Enabled" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:enabled"}
|
||||||
|
Switch Cap_1_Connected "Connected" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:connected"}
|
||||||
|
DateTime Cap_1_Last_Link_Down_Time "Last link down" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:lastLinkDownTime"}
|
||||||
|
DateTime Cap_1_Last_Link_Up_Time "Last link up" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:lastLinkUpTime"}
|
||||||
|
Number Cap_1_Link_Downs "Link downs" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:linkDowns"}
|
||||||
|
Number:DataTransferRate Cap_1_Tx_Rate "Transmission rate" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txRate"}
|
||||||
|
Number:DataTransferRate Cap_1_Rx_Rate "Receiving rate" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxRate"}
|
||||||
|
Number Cap_1_Tx_Packet_Rate "Transmission packet rate" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txPacketRate"}
|
||||||
|
Number Cap_1_Rx_Packet_Rate "Receiving packet rate" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxPacketRate"}
|
||||||
|
Number:DataAmount Cap_1_Tx_Bytes "Transmitted bytes" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txBytes"}
|
||||||
|
Number:DataAmount Cap_1_Rx_Bytes "Received bytes" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxBytes"}
|
||||||
|
Number Cap_1_Tx_Packets "Transmitted packets" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txPackets"}
|
||||||
|
Number Cap_1_Rx_Packets "Received packets" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxPackets"}
|
||||||
|
Number Cap_1_Tx_Drops "Transmission drops" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txDrops"}
|
||||||
|
Number Cap_1_Rx_Drops "Receiving drops" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxDrops"}
|
||||||
|
Number Cap_1_Tx_Errors "Transmission errors" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:txErrors"}
|
||||||
|
Number Cap_1_Rx_Errors "Receiving errors" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:rxErrors"}
|
||||||
|
String Cap_1_State "State" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:state"}
|
||||||
|
Number Cap_1_Registered_Clients "Registered clients" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:registeredClients"}
|
||||||
|
Number Cap_1_Authorized_Clients "Authorized clients" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:authorizedClients"}
|
||||||
|
DateTime Cap_1_Up_Since "Up since" (gRB1Cap1) {channel="mikrotik:interface:rb1:cap1:upSince"}
|
||||||
|
|
||||||
|
Group gRB1Ppp1 "PPPoE Client 1"
|
||||||
|
String PP_Po_E_1_Type "Type" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:type"}
|
||||||
|
String PP_Po_E_1_Name "Name" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:name"}
|
||||||
|
String PP_Po_E_1_Comment "Comment" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:comment"}
|
||||||
|
String PP_Po_E_1_Mac_Address "Mac address" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:macAddress"}
|
||||||
|
Switch PP_Po_E_1_Enabled "Enabled" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:enabled"}
|
||||||
|
Switch PP_Po_E_1_Connected "Connected" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:connected"}
|
||||||
|
DateTime PP_Po_E_1_Last_Link_Down_Time "Last link down" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:lastLinkDownTime"}
|
||||||
|
DateTime PP_Po_E_1_Last_Link_Up_Time "Last link up" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:lastLinkUpTime"}
|
||||||
|
Number PP_Po_E_1_Link_Downs "Link downs" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:linkDowns"}
|
||||||
|
Number:DataTransferRate PP_Po_E_1_Tx_Rate "Transmission rate" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txRate"}
|
||||||
|
Number:DataTransferRate PP_Po_E_1_Rx_Rate "Receiving rate" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxRate"}
|
||||||
|
Number PP_Po_E_1_Tx_Packet_Rate "Transmission packet rate" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txPacketRate"}
|
||||||
|
Number PP_Po_E_1_Rx_Packet_Rate "Receiving packet rate" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxPacketRate"}
|
||||||
|
Number:DataAmount PP_Po_E_1_Tx_Bytes "Transmitted bytes" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txBytes"}
|
||||||
|
Number:DataAmount PP_Po_E_1_Rx_Bytes "Received bytes" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxBytes"}
|
||||||
|
Number PP_Po_E_1_Tx_Packets "Transmitted packets" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txPackets"}
|
||||||
|
Number PP_Po_E_1_Rx_Packets "Received packets" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxPackets"}
|
||||||
|
Number PP_Po_E_1_Tx_Drops "Transmission drops" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txDrops"}
|
||||||
|
Number PP_Po_E_1_Rx_Drops "Receiving drops" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxDrops"}
|
||||||
|
Number PP_Po_E_1_Tx_Errors "Transmission errors" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:txErrors"}
|
||||||
|
Number PP_Po_E_1_Rx_Errors "Receiving errors" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:rxErrors"}
|
||||||
|
String PP_Po_E_1_State "State" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:state"}
|
||||||
|
DateTime PP_Po_E_1_Up_Since "Up since" (gRB1Ppp1) {channel="mikrotik:interface:rb1:ppp1:upSince"}
|
||||||
|
|
||||||
|
Group gRB1Tun1 "L2TP Server 1"
|
||||||
|
String L_2_TP_Srv_1_Type "Type" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:type"}
|
||||||
|
String L_2_TP_Srv_1_Name "Name" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:name"}
|
||||||
|
String L_2_TP_Srv_1_Comment "Comment" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:comment"}
|
||||||
|
String L_2_TP_Srv_1_Mac_Address "Mac address" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:macAddress"}
|
||||||
|
Switch L_2_TP_Srv_1_Enabled "Enabled" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:enabled"}
|
||||||
|
Switch L_2_TP_Srv_1_Connected "Connected" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:connected"}
|
||||||
|
DateTime L_2_TP_Srv_1_Last_Link_Down_Time "Last link down" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:lastLinkDownTime"}
|
||||||
|
DateTime L_2_TP_Srv_1_Last_Link_Up_Time "Last link up" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:lastLinkUpTime"}
|
||||||
|
Number L_2_TP_Srv_1_Link_Downs "Link downs" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:linkDowns"}
|
||||||
|
Number:DataTransferRate L_2_TP_Srv_1_Tx_Rate "Transmission rate" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txRate"}
|
||||||
|
Number:DataTransferRate L_2_TP_Srv_1_Rx_Rate "Receiving rate" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxRate"}
|
||||||
|
Number L_2_TP_Srv_1_Tx_Packet_Rate "Transmission packet rate" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txPacketRate"}
|
||||||
|
Number L_2_TP_Srv_1_Rx_Packet_Rate "Receiving packet rate" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxPacketRate"}
|
||||||
|
Number:DataAmount L_2_TP_Srv_1_Tx_Bytes "Transmitted bytes" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txBytes"}
|
||||||
|
Number:DataAmount L_2_TP_Srv_1_Rx_Bytes "Received bytes" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxBytes"}
|
||||||
|
Number L_2_TP_Srv_1_Tx_Packets "Transmitted packets" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txPackets"}
|
||||||
|
Number L_2_TP_Srv_1_Rx_Packets "Received packets" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxPackets"}
|
||||||
|
Number L_2_TP_Srv_1_Tx_Drops "Transmission drops" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txDrops"}
|
||||||
|
Number L_2_TP_Srv_1_Rx_Drops "Receiving drops" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxDrops"}
|
||||||
|
Number L_2_TP_Srv_1_Tx_Errors "Transmission errors" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:txErrors"}
|
||||||
|
Number L_2_TP_Srv_1_Rx_Errors "Receiving errors" (gRB1Tun1) {channel="mikrotik:interface:rb1:tun1:rxErrors"}
|
||||||
|
|
||||||
|
Group gRB1Wifi1 "WiFi Client 1"
|
||||||
|
String Phone_1_Mac_Address "Mac address" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:macAddress"}
|
||||||
|
String Phone_1_Comment "Comment" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:comment"}
|
||||||
|
Switch Phone_1_Connected "Connected" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:connected"}
|
||||||
|
Switch Phone_1_Continuous "Continuous" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:continuous"}
|
||||||
|
String Phone_1_Ssid "Wi fi network" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:ssid"}
|
||||||
|
String Phone_1_Interface "Name" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:interface"}
|
||||||
|
Number Phone_1_Signal "Received signal strength indicator" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:signal"}
|
||||||
|
DateTime Phone_1_Up_Since "Up since" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:upSince"}
|
||||||
|
DateTime Phone_1_Last_Seen "Last seen" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:lastSeen"}
|
||||||
|
Number:DataTransferRate Phone_1_Tx_Rate "Transmission rate" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:txRate"}
|
||||||
|
Number:DataTransferRate Phone_1_Rx_Rate "Receiving rate" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:rxRate"}
|
||||||
|
Number Phone_1_Tx_Packet_Rate "Transmission packet rate" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:txPacketRate"}
|
||||||
|
Number Phone_1_Rx_Packet_Rate "Receiving packet rate" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:rxPacketRate"}
|
||||||
|
Number:DataAmount Phone_1_Tx_Bytes "Transmitted bytes" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:txBytes"}
|
||||||
|
Number:DataAmount Phone_1_Rx_Bytes "Received bytes" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:rxBytes"}
|
||||||
|
Number Phone_1_Tx_Packets "Transmitted packets" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:txPackets"}
|
||||||
|
Number Phone_1_Rx_Packets "Received packets" (gRB1Wifi1) {channel="mikrotik:wifiRegistration:rb1:wifi1:rxPackets"}
|
||||||
|
|
||||||
|
Group gRB1Wifi2 "WiFi Client 2"
|
||||||
|
String Tablet_2_Mac_Address "Mac address" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:macAddress"}
|
||||||
|
String Tablet_2_Comment "Comment" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:comment"}
|
||||||
|
Switch Tablet_2_Connected "Connected" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:connected"}
|
||||||
|
Switch Tablet_2_Continuous "Continuous" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:continuous"}
|
||||||
|
String Tablet_2_Ssid "Wi fi network" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:ssid"}
|
||||||
|
String Tablet_2_Interface "Name" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:interface"}
|
||||||
|
Number Tablet_2_Signal "Received signal strength indicator" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:signal"}
|
||||||
|
DateTime Tablet_2_Up_Since "Up since" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:upSince"}
|
||||||
|
DateTime Tablet_2_Last_Seen "Last seen" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:lastSeen"}
|
||||||
|
Number:DataTransferRate Tablet_2_Tx_Rate "Transmission rate" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:txRate"}
|
||||||
|
Number:DataTransferRate Tablet_2_Rx_Rate "Receiving rate" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:rxRate"}
|
||||||
|
Number Tablet_2_Tx_Packet_Rate "Transmission packet rate" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:txPacketRate"}
|
||||||
|
Number Tablet_2_Rx_Packet_Rate "Receiving packet rate" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:rxPacketRate"}
|
||||||
|
Number:DataAmount Tablet_2_Tx_Bytes "Transmitted bytes" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:txBytes"}
|
||||||
|
Number:DataAmount Tablet_2_Rx_Bytes "Received bytes" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:rxBytes"}
|
||||||
|
Number Tablet_2_Tx_Packets "Transmitted packets" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:txPackets"}
|
||||||
|
Number Tablet_2_Rx_Packets "Received packets" (gRB1Wifi2) {channel="mikrotik:wifiRegistration:rb1:wifi2:rxPackets"}
|
||||||
|
```
|
||||||
|
|
||||||
|
_sitemaps/mikrotik.sitemap_
|
||||||
|
|
||||||
|
```
|
||||||
|
sitemap mikrotik label="Mikrotik Binding Demo"
|
||||||
|
{
|
||||||
|
Frame label="RouterBOARD 1" {
|
||||||
|
Group item=gRB1
|
||||||
|
Group item=gRB1Eth1
|
||||||
|
Group item=gRB1Eth2
|
||||||
|
Group item=gRB1Ppp1
|
||||||
|
Group item=gRB1Tun1
|
||||||
|
Group item=gRB1Cap1
|
||||||
|
Group item=gRB1Wifi1
|
||||||
|
Group item=gRB1Wifi2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
26
bundles/org.openhab.binding.mikrotik/pom.xml
Normal file
26
bundles/org.openhab.binding.mikrotik/pom.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||||
|
<version>3.2.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>org.openhab.binding.mikrotik</artifactId>
|
||||||
|
|
||||||
|
<name>openHAB Add-ons :: Bundles :: Mikrotik Binding</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.legrange</groupId>
|
||||||
|
<artifactId>mikrotik</artifactId>
|
||||||
|
<version>3.0.7</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<features name="org.openhab.binding.mikrotik-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||||
|
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||||
|
|
||||||
|
<feature name="openhab-binding-mikrotik" description="Mikrotik Binding" version="${project.version}">
|
||||||
|
<feature>openhab-runtime-base</feature>
|
||||||
|
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.mikrotik/${project.version}</bundle>
|
||||||
|
</feature>
|
||||||
|
</features>
|
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikBindingConstants} class defines common constants, which are
|
||||||
|
* used across the whole binding.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MikrotikBindingConstants {
|
||||||
|
|
||||||
|
private static final String BINDING_ID = "mikrotik";
|
||||||
|
|
||||||
|
public static final String PROPERTY_MODEL = "modelId";
|
||||||
|
public static final String PROPERTY_FIRMWARE = "firmware";
|
||||||
|
public static final String PROPERTY_SERIAL_NUMBER = "serial";
|
||||||
|
|
||||||
|
// List of all Thing Types
|
||||||
|
public static final ThingTypeUID THING_TYPE_ROUTEROS = new ThingTypeUID(BINDING_ID, "routeros");
|
||||||
|
public static final ThingTypeUID THING_TYPE_INTERFACE = new ThingTypeUID(BINDING_ID, "interface");
|
||||||
|
public static final ThingTypeUID THING_TYPE_WIRELESS_CLIENT = new ThingTypeUID(BINDING_ID, "wifiRegistration");
|
||||||
|
|
||||||
|
// RouterOS system stats
|
||||||
|
public static final String CHANNEL_FREE_SPACE = "freeSpace";
|
||||||
|
public static final String CHANNEL_TOTAL_SPACE = "totalSpace";
|
||||||
|
public static final String CHANNEL_USED_SPACE = "usedSpace";
|
||||||
|
public static final String CHANNEL_FREE_MEM = "freeMemory";
|
||||||
|
public static final String CHANNEL_TOTAL_MEM = "totalMemory";
|
||||||
|
public static final String CHANNEL_USED_MEM = "usedMemory";
|
||||||
|
public static final String CHANNEL_CPU_LOAD = "cpuLoad";
|
||||||
|
|
||||||
|
public static final String CHANNEL_COMMENT = "comment";
|
||||||
|
|
||||||
|
// List of common interface channels
|
||||||
|
public static final String CHANNEL_NAME = "name";
|
||||||
|
public static final String CHANNEL_TYPE = "type";
|
||||||
|
public static final String CHANNEL_MAC = "macAddress";
|
||||||
|
public static final String CHANNEL_ENABLED = "enabled";
|
||||||
|
public static final String CHANNEL_CONNECTED = "connected"; // used for wifi client as well
|
||||||
|
public static final String CHANNEL_LAST_LINK_DOWN_TIME = "lastLinkDownTime";
|
||||||
|
public static final String CHANNEL_LAST_LINK_UP_TIME = "lastLinkUpTime";
|
||||||
|
public static final String CHANNEL_LINK_DOWNS = "linkDowns";
|
||||||
|
public static final String CHANNEL_TX_DATA_RATE = "txRate";
|
||||||
|
public static final String CHANNEL_RX_DATA_RATE = "rxRate";
|
||||||
|
public static final String CHANNEL_TX_PACKET_RATE = "txPacketRate";
|
||||||
|
public static final String CHANNEL_RX_PACKET_RATE = "rxPacketRate";
|
||||||
|
public static final String CHANNEL_TX_BYTES = "txBytes";
|
||||||
|
public static final String CHANNEL_RX_BYTES = "rxBytes";
|
||||||
|
public static final String CHANNEL_TX_PACKETS = "txPackets";
|
||||||
|
public static final String CHANNEL_RX_PACKETS = "rxPackets";
|
||||||
|
public static final String CHANNEL_TX_DROPS = "txDrops";
|
||||||
|
public static final String CHANNEL_RX_DROPS = "rxDrops";
|
||||||
|
public static final String CHANNEL_TX_ERRORS = "txErrors";
|
||||||
|
public static final String CHANNEL_RX_ERRORS = "rxErrors";
|
||||||
|
|
||||||
|
// Ethernet interface channel list
|
||||||
|
public static final String CHANNEL_DEFAULT_NAME = "defaultName";
|
||||||
|
public static final String CHANNEL_RATE = "rate";
|
||||||
|
|
||||||
|
// CAPsMAN interface channel list
|
||||||
|
public static final String CHANNEL_INTERFACE = "interface";
|
||||||
|
public static final String CHANNEL_STATE = "state";
|
||||||
|
public static final String CHANNEL_REGISTERED_CLIENTS = "registeredClients";
|
||||||
|
public static final String CHANNEL_AUTHORIZED_CLIENTS = "authorizedClients";
|
||||||
|
public static final String CHANNEL_CONTINUOUS = "continuous";
|
||||||
|
|
||||||
|
// PPP interface shared channel list
|
||||||
|
public static final String CHANNEL_UP_SINCE = "upSince";
|
||||||
|
|
||||||
|
// Wireless client channels
|
||||||
|
public static final String CHANNEL_LAST_SEEN = "lastSeen";
|
||||||
|
public static final String CHANNEL_SSID = "ssid";
|
||||||
|
public static final String CHANNEL_SIGNAL = "signal";
|
||||||
|
|
||||||
|
// List of common wired + wireless client channels
|
||||||
|
public static final String CHANNEL_SITE = "site";
|
||||||
|
public static final String CHANNEL_IP_ADDRESS = "ipAddress";
|
||||||
|
public static final String CHANNEL_BLOCKED = "blocked";
|
||||||
|
public static final String CHANNEL_RECONNECT = "reconnect";
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.handler.MikrotikInterfaceThingHandler;
|
||||||
|
import org.openhab.binding.mikrotik.internal.handler.MikrotikRouterosBridgeHandler;
|
||||||
|
import org.openhab.binding.mikrotik.internal.handler.MikrotikWirelessClientThingHandler;
|
||||||
|
import org.openhab.core.thing.Bridge;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
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.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikHandlerFactory} is responsible for creating things and thing
|
||||||
|
* handlers.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
@Component(configurationPid = "binding.mikrotik", service = ThingHandlerFactory.class)
|
||||||
|
public class MikrotikHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
@Override
|
||||||
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return MikrotikRouterosBridgeHandler.supportsThingType(thingTypeUID)
|
||||||
|
|| MikrotikWirelessClientThingHandler.supportsThingType(thingTypeUID)
|
||||||
|
|| MikrotikInterfaceThingHandler.supportsThingType(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
if (MikrotikRouterosBridgeHandler.supportsThingType(thingTypeUID)) {
|
||||||
|
return new MikrotikRouterosBridgeHandler((Bridge) thing);
|
||||||
|
} else if (MikrotikWirelessClientThingHandler.supportsThingType(thingTypeUID)) {
|
||||||
|
return new MikrotikWirelessClientThingHandler(thing);
|
||||||
|
} else if (MikrotikInterfaceThingHandler.supportsThingType(thingTypeUID)) {
|
||||||
|
return new MikrotikInterfaceThingHandler(thing);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ConfigValidation} interface should be implemented by all config objects, so the thing handlers could
|
||||||
|
* change their state properly, based on the config validation result.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public interface ConfigValidation {
|
||||||
|
boolean isValid();
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link InterfaceThingConfig} class contains fields mapping thing configuration parameters for
|
||||||
|
* network interface things.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class InterfaceThingConfig implements ConfigValidation {
|
||||||
|
public String name = "";
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return !name.isBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("InterfaceThingConfig{name=%s}", name);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosThingConfig} class contains fields mapping thing configuration parameters for
|
||||||
|
* RouterOS bridge thing.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosThingConfig implements ConfigValidation {
|
||||||
|
public String host = "rb3011";
|
||||||
|
public int port = 8728;
|
||||||
|
public String login = "admin";
|
||||||
|
public String password = "";
|
||||||
|
public int refresh = 10;
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return !host.isBlank() && !login.isBlank() && !password.isBlank() && refresh > 0 && port > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("RouterosThingConfig{host=%s, port=%d, login=%s, password=*****, refresh=%ds}", host, port,
|
||||||
|
login, refresh);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link WirelessClientThingConfig} class contains fields mapping thing configuration parameters for
|
||||||
|
* WiFi client thing.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class WirelessClientThingConfig implements ConfigValidation {
|
||||||
|
public String mac = "";
|
||||||
|
public String ssid = "";
|
||||||
|
public int considerContinuous = 180;
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return !mac.isBlank() && considerContinuous > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("WirelessClientThingConfig{mac=%s, ssid=%s, considerContinuous=%ds}", mac, ssid,
|
||||||
|
considerContinuous);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.handler;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ChannelUpdateException} is used to bubble up channel update errors which are mainly
|
||||||
|
* happens during data conversion. But those errors should not bring bridge offline and break normal
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class ChannelUpdateException extends RuntimeException {
|
||||||
|
static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final ThingUID thingUID;
|
||||||
|
private final ChannelUID channelID;
|
||||||
|
|
||||||
|
public ChannelUpdateException(ThingUID thingUID, ChannelUID channelUID, Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
this.thingUID = thingUID;
|
||||||
|
this.channelID = channelUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getMessage() {
|
||||||
|
return String.format("%s @ %s/%s", super.getMessage(), thingUID, channelID);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,246 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.core.thing.ThingStatus.OFFLINE;
|
||||||
|
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
||||||
|
import static org.openhab.core.thing.ThingStatusDetail.CONFIGURATION_ERROR;
|
||||||
|
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
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.binding.mikrotik.internal.config.ConfigValidation;
|
||||||
|
import org.openhab.binding.mikrotik.internal.config.RouterosThingConfig;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosDevice;
|
||||||
|
import org.openhab.core.cache.ExpiringCache;
|
||||||
|
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.thing.binding.builder.ThingStatusInfoBuilder;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikBaseThingHandler} is a base class for all other RouterOS things of map-value nature.
|
||||||
|
* It is responsible for handling commands, which are sent to one of the channels and emit channel updates
|
||||||
|
* whenever required.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param <C> config - the config class used by this base thing handler
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public abstract class MikrotikBaseThingHandler<C extends ConfigValidation> extends BaseThingHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(MikrotikBaseThingHandler.class);
|
||||||
|
protected @Nullable C config;
|
||||||
|
private @Nullable ScheduledFuture<?> refreshJob;
|
||||||
|
protected ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofDays(1), () -> false);
|
||||||
|
protected Map<String, State> currentState = new HashMap<>();
|
||||||
|
|
||||||
|
// public static boolean supportsThingType(ThingTypeUID thingTypeUID) <- in subclasses
|
||||||
|
|
||||||
|
public MikrotikBaseThingHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable MikrotikRouterosBridgeHandler getVerifiedBridgeHandler() {
|
||||||
|
Bridge bridgeRef = getBridge();
|
||||||
|
if (bridgeRef != null && bridgeRef.getHandler() != null
|
||||||
|
&& (bridgeRef.getHandler() instanceof MikrotikRouterosBridgeHandler)) {
|
||||||
|
return (MikrotikRouterosBridgeHandler) bridgeRef.getHandler();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @Nullable RouterosDevice getRouterOs() {
|
||||||
|
MikrotikRouterosBridgeHandler bridgeHandler = getVerifiedBridgeHandler();
|
||||||
|
return bridgeHandler == null ? null : bridgeHandler.getRouteros();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
logger.debug("Handling command = {} for channel = {}", command, channelUID);
|
||||||
|
if (getThing().getStatus() == ONLINE) {
|
||||||
|
RouterosDevice routeros = getRouterOs();
|
||||||
|
if (routeros != null) {
|
||||||
|
if (command == REFRESH) {
|
||||||
|
refreshCache.getValue();
|
||||||
|
refreshChannel(channelUID);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
executeCommand(channelUID, command);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.warn("Unexpected error handling command = {} for channel = {} : {}", command, channelUID,
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
cancelRefreshJob();
|
||||||
|
if (getVerifiedBridgeHandler() == null) {
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "This thing requires a RouterOS bridge");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var superKlass = (ParameterizedType) getClass().getGenericSuperclass();
|
||||||
|
if (superKlass == null) {
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
|
"getGenericSuperclass failed for thing handler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Class<?> klass = (Class<?>) (superKlass.getActualTypeArguments()[0]);
|
||||||
|
|
||||||
|
C localConfig = (C) getConfigAs(klass);
|
||||||
|
this.config = localConfig;
|
||||||
|
|
||||||
|
if (!localConfig.isValid()) {
|
||||||
|
updateStatus(OFFLINE, CONFIGURATION_ERROR, String.format("%s is invalid", klass.getSimpleName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatus(ONLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
|
||||||
|
if (status == ONLINE || (status == OFFLINE && statusDetail == ThingStatusDetail.COMMUNICATION_ERROR)) {
|
||||||
|
scheduleRefreshJob();
|
||||||
|
} else if (status == OFFLINE
|
||||||
|
&& (statusDetail == ThingStatusDetail.CONFIGURATION_ERROR || statusDetail == ThingStatusDetail.GONE)) {
|
||||||
|
cancelRefreshJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the status only if it's changed
|
||||||
|
ThingStatusInfo statusInfo = ThingStatusInfoBuilder.create(status, statusDetail).withDescription(description)
|
||||||
|
.build();
|
||||||
|
if (!statusInfo.equals(getThing().getStatusInfo())) {
|
||||||
|
super.updateStatus(status, statusDetail, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
private void scheduleRefreshJob() {
|
||||||
|
synchronized (this) {
|
||||||
|
if (refreshJob == null) {
|
||||||
|
var bridgeHandler = getVerifiedBridgeHandler();
|
||||||
|
if (bridgeHandler == null) {
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Cannot obtain bridge handler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RouterosThingConfig bridgeConfig = bridgeHandler.getBridgeConfig();
|
||||||
|
int refreshPeriod = bridgeConfig.refresh;
|
||||||
|
logger.debug("Scheduling refresh job every {}s", refreshPeriod);
|
||||||
|
|
||||||
|
this.refreshCache = new ExpiringCache<>(Duration.ofSeconds(refreshPeriod), this::verifiedRefreshModels);
|
||||||
|
refreshJob = scheduler.scheduleWithFixedDelay(this::scheduledRun, refreshPeriod, refreshPeriod,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelRefreshJob() {
|
||||||
|
synchronized (this) {
|
||||||
|
var job = this.refreshJob;
|
||||||
|
if (job != null) {
|
||||||
|
logger.debug("Cancelling refresh job");
|
||||||
|
job.cancel(true);
|
||||||
|
this.refreshJob = null;
|
||||||
|
// Not setting to null as getValue() can potentially be called after
|
||||||
|
this.refreshCache = new ExpiringCache<>(Duration.ofDays(1), () -> false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduledRun() {
|
||||||
|
MikrotikRouterosBridgeHandler bridgeHandler = getVerifiedBridgeHandler();
|
||||||
|
if (bridgeHandler == null) {
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "Failed reaching out to RouterOS bridge");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bridge bridge = getBridge();
|
||||||
|
if (bridge != null && bridge.getStatus() == OFFLINE) {
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "The RouterOS bridge is currently offline");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getThing().getStatus() != ONLINE) {
|
||||||
|
updateStatus(ONLINE);
|
||||||
|
}
|
||||||
|
logger.debug("Refreshing all {} channels", getThing().getUID());
|
||||||
|
for (Channel channel : getThing().getChannels()) {
|
||||||
|
try {
|
||||||
|
refreshChannel(channel.getUID());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.warn("Unhandled exception while refreshing the {} Mikrotik thing", getThing().getUID(), e);
|
||||||
|
updateStatus(OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void refresh() throws ChannelUpdateException {
|
||||||
|
if (getThing().getStatus() == ONLINE) {
|
||||||
|
if (getRouterOs() != null) {
|
||||||
|
refreshCache.getValue();
|
||||||
|
for (Channel channel : getThing().getChannels()) {
|
||||||
|
ChannelUID channelUID = channel.getUID();
|
||||||
|
try {
|
||||||
|
refreshChannel(channelUID);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
throw new ChannelUpdateException(getThing().getUID(), channelUID, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean verifiedRefreshModels() {
|
||||||
|
if (getRouterOs() != null && config != null) {
|
||||||
|
refreshModels();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
cancelRefreshJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void refreshModels();
|
||||||
|
|
||||||
|
protected abstract void refreshChannel(ChannelUID channelUID);
|
||||||
|
|
||||||
|
protected abstract void executeCommand(ChannelUID channelUID, Command command);
|
||||||
|
}
|
@ -0,0 +1,316 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.core.thing.ThingStatus.OFFLINE;
|
||||||
|
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
||||||
|
import static org.openhab.core.thing.ThingStatusDetail.GONE;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.MikrotikBindingConstants;
|
||||||
|
import org.openhab.binding.mikrotik.internal.config.InterfaceThingConfig;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosCapInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosDevice;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosEthernetInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosInterfaceBase;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosL2TPCliInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosL2TPSrvInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosPPPoECliInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosWlanInterface;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.RateCalculator;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.StateUtil;
|
||||||
|
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.ThingTypeUID;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikInterfaceThingHandler} is a {@link MikrotikBaseThingHandler} subclass that wraps shared
|
||||||
|
* functionality for all interface things of different types. It is responsible for handling commands, which are
|
||||||
|
* sent to one of the channels and emit channel updates whenever required.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MikrotikInterfaceThingHandler extends MikrotikBaseThingHandler<InterfaceThingConfig> {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(MikrotikInterfaceThingHandler.class);
|
||||||
|
|
||||||
|
private @Nullable RouterosInterfaceBase iface;
|
||||||
|
|
||||||
|
private final RateCalculator txByteRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator rxByteRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator txPacketRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator rxPacketRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
public static boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return MikrotikBindingConstants.THING_TYPE_INTERFACE.equals(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MikrotikInterfaceThingHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
|
||||||
|
RouterosDevice routeros = getRouterOs();
|
||||||
|
InterfaceThingConfig cfg = this.config;
|
||||||
|
if (routeros != null && cfg != null) {
|
||||||
|
if (status == ONLINE || (status == OFFLINE && statusDetail == ThingStatusDetail.COMMUNICATION_ERROR)) {
|
||||||
|
routeros.registerForMonitoring(cfg.name);
|
||||||
|
} else if (status == OFFLINE
|
||||||
|
&& (statusDetail == ThingStatusDetail.CONFIGURATION_ERROR || statusDetail == GONE)) {
|
||||||
|
routeros.unregisterForMonitoring(cfg.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.updateStatus(status, statusDetail, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshModels() {
|
||||||
|
RouterosDevice routeros = getRouterOs();
|
||||||
|
InterfaceThingConfig cfg = this.config;
|
||||||
|
if (routeros != null && cfg != null) {
|
||||||
|
RouterosInterfaceBase rosInterface = routeros.findInterface(cfg.name);
|
||||||
|
this.iface = rosInterface;
|
||||||
|
if (rosInterface == null) {
|
||||||
|
String statusMsg = String.format("Interface %s is not found in RouterOS for thing %s", cfg.name,
|
||||||
|
getThing().getUID());
|
||||||
|
updateStatus(OFFLINE, GONE, statusMsg);
|
||||||
|
} else {
|
||||||
|
txByteRate.update(rosInterface.getTxBytes());
|
||||||
|
rxByteRate.update(rosInterface.getRxBytes());
|
||||||
|
txPacketRate.update(rosInterface.getTxPackets());
|
||||||
|
rxPacketRate.update(rosInterface.getRxPackets());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshChannel(ChannelUID channelUID) {
|
||||||
|
String channelID = channelUID.getIdWithoutGroup();
|
||||||
|
State oldState = currentState.getOrDefault(channelID, UnDefType.NULL);
|
||||||
|
State newState = oldState;
|
||||||
|
RouterosInterfaceBase iface = this.iface;
|
||||||
|
if (iface == null) {
|
||||||
|
newState = UnDefType.NULL;
|
||||||
|
} else {
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_NAME:
|
||||||
|
newState = StateUtil.stringOrNull(iface.getName());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_COMMENT:
|
||||||
|
newState = StateUtil.stringOrNull(iface.getComment());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TYPE:
|
||||||
|
newState = StateUtil.stringOrNull(iface.getType());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_MAC:
|
||||||
|
newState = StateUtil.stringOrNull(iface.getMacAddress());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_ENABLED:
|
||||||
|
newState = StateUtil.boolOrNull(iface.isEnabled());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_CONNECTED:
|
||||||
|
newState = StateUtil.boolOrNull(iface.isConnected());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_LAST_LINK_DOWN_TIME:
|
||||||
|
newState = StateUtil.timeOrNull(iface.getLastLinkDownTime());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_LAST_LINK_UP_TIME:
|
||||||
|
newState = StateUtil.timeOrNull(iface.getLastLinkUpTime());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_LINK_DOWNS:
|
||||||
|
newState = StateUtil.intOrNull(iface.getLinkDowns());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_DATA_RATE:
|
||||||
|
newState = StateUtil.qtyMegabitPerSecOrNull(txByteRate.getMegabitRate());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_DATA_RATE:
|
||||||
|
newState = StateUtil.qtyMegabitPerSecOrNull(rxByteRate.getMegabitRate());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_PACKET_RATE:
|
||||||
|
newState = StateUtil.floatOrNull(txPacketRate.getRate());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_PACKET_RATE:
|
||||||
|
newState = StateUtil.floatOrNull(rxPacketRate.getRate());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_BYTES:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getTxBytes());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_BYTES:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getRxBytes());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_PACKETS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getTxPackets());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_PACKETS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getRxPackets());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_DROPS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getTxDrops());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_DROPS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getRxDrops());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TX_ERRORS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getTxErrors());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RX_ERRORS:
|
||||||
|
newState = StateUtil.bigIntOrNull(iface.getRxErrors());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (iface instanceof RouterosEthernetInterface) {
|
||||||
|
newState = getEtherIterfaceChannelState(channelID);
|
||||||
|
} else if (iface instanceof RouterosCapInterface) {
|
||||||
|
newState = getCapIterfaceChannelState(channelID);
|
||||||
|
} else if (iface instanceof RouterosWlanInterface) {
|
||||||
|
newState = getWlanIterfaceChannelState(channelID);
|
||||||
|
} else if (iface instanceof RouterosPPPoECliInterface) {
|
||||||
|
newState = getPPPoECliChannelState(channelID);
|
||||||
|
} else if (iface instanceof RouterosL2TPSrvInterface) {
|
||||||
|
newState = getL2TPSrvChannelState(channelID);
|
||||||
|
} else if (iface instanceof RouterosL2TPCliInterface) {
|
||||||
|
newState = getL2TPCliChannelState(channelID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newState.equals(oldState)) {
|
||||||
|
updateState(channelID, newState);
|
||||||
|
currentState.put(channelID, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getEtherIterfaceChannelState(String channelID) {
|
||||||
|
RouterosEthernetInterface etherIface = (RouterosEthernetInterface) this.iface;
|
||||||
|
if (etherIface == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_DEFAULT_NAME:
|
||||||
|
return StateUtil.stringOrNull(etherIface.getDefaultName());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(etherIface.getState());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RATE:
|
||||||
|
return StateUtil.stringOrNull(etherIface.getRate());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getCapIterfaceChannelState(String channelID) {
|
||||||
|
RouterosCapInterface capIface = (RouterosCapInterface) this.iface;
|
||||||
|
if (capIface == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(capIface.getCurrentState());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RATE:
|
||||||
|
return StateUtil.stringOrNull(capIface.getRateSet());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_REGISTERED_CLIENTS:
|
||||||
|
return StateUtil.intOrNull(capIface.getRegisteredClients());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_AUTHORIZED_CLIENTS:
|
||||||
|
return StateUtil.intOrNull(capIface.getAuthorizedClients());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getWlanIterfaceChannelState(String channelID) {
|
||||||
|
RouterosWlanInterface wlIface = (RouterosWlanInterface) this.iface;
|
||||||
|
if (wlIface == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(wlIface.getCurrentState());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_RATE:
|
||||||
|
return StateUtil.stringOrNull(wlIface.getRate());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_REGISTERED_CLIENTS:
|
||||||
|
return StateUtil.intOrNull(wlIface.getRegisteredClients());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_AUTHORIZED_CLIENTS:
|
||||||
|
return StateUtil.intOrNull(wlIface.getAuthorizedClients());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getPPPoECliChannelState(String channelID) {
|
||||||
|
RouterosPPPoECliInterface pppCli = (RouterosPPPoECliInterface) this.iface;
|
||||||
|
if (pppCli == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(pppCli.getStatus());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_UP_SINCE:
|
||||||
|
return StateUtil.timeOrNull(pppCli.getUptimeStart());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getL2TPSrvChannelState(String channelID) {
|
||||||
|
RouterosL2TPSrvInterface vpnSrv = (RouterosL2TPSrvInterface) this.iface;
|
||||||
|
if (vpnSrv == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(vpnSrv.getEncoding());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_UP_SINCE:
|
||||||
|
return StateUtil.timeOrNull(vpnSrv.getUptimeStart());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getL2TPCliChannelState(String channelID) {
|
||||||
|
RouterosL2TPCliInterface vpnCli = (RouterosL2TPCliInterface) this.iface;
|
||||||
|
if (vpnCli == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_STATE:
|
||||||
|
return StateUtil.stringOrNull(vpnCli.getEncoding());
|
||||||
|
case MikrotikBindingConstants.CHANNEL_UP_SINCE:
|
||||||
|
return StateUtil.timeOrNull(vpnCli.getUptimeStart());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeCommand(ChannelUID channelUID, Command command) {
|
||||||
|
if (iface == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.warn("Ignoring unsupported command = {} for channel = {}", command, channelUID);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,292 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
||||||
|
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
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.binding.mikrotik.internal.MikrotikBindingConstants;
|
||||||
|
import org.openhab.binding.mikrotik.internal.config.RouterosThingConfig;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosDevice;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosRouterboardInfo;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosSystemResources;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.StateUtil;
|
||||||
|
import org.openhab.core.thing.Bridge;
|
||||||
|
import org.openhab.core.thing.Channel;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import me.legrange.mikrotik.MikrotikApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikRouterosBridgeHandler} is a main binding class that wraps a {@link RouterosDevice} and
|
||||||
|
* manages fetching data from RouterOS. It is also responsible for updating brindge thing properties and
|
||||||
|
* handling commands, which are sent to one of the channels and emit channel updates whenever required.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MikrotikRouterosBridgeHandler extends BaseBridgeHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(MikrotikRouterosBridgeHandler.class);
|
||||||
|
private @Nullable RouterosThingConfig config;
|
||||||
|
private @Nullable volatile RouterosDevice routeros;
|
||||||
|
private @Nullable ScheduledFuture<?> refreshJob;
|
||||||
|
private Map<String, State> currentState = new HashMap<>();
|
||||||
|
|
||||||
|
public static boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return MikrotikBindingConstants.THING_TYPE_ROUTEROS.equals(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MikrotikRouterosBridgeHandler(Bridge bridge) {
|
||||||
|
super(bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
cancelRefreshJob();
|
||||||
|
var cfg = getConfigAs(RouterosThingConfig.class);
|
||||||
|
this.config = cfg;
|
||||||
|
logger.debug("Initializing MikrotikRouterosBridgeHandler with config = {}", cfg);
|
||||||
|
if (cfg.isValid()) {
|
||||||
|
this.routeros = new RouterosDevice(cfg.host, cfg.port, cfg.login, cfg.password);
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, String.format("Connecting to %s", cfg.host));
|
||||||
|
scheduleRefreshJob();
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Configuration is not valid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosDevice getRouteros() {
|
||||||
|
return routeros;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosThingConfig getBridgeConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
|
||||||
|
if (status == ThingStatus.ONLINE
|
||||||
|
|| (status == ThingStatus.OFFLINE && statusDetail == ThingStatusDetail.COMMUNICATION_ERROR)) {
|
||||||
|
scheduleRefreshJob();
|
||||||
|
} else if (status == ThingStatus.OFFLINE && statusDetail == ThingStatusDetail.CONFIGURATION_ERROR) {
|
||||||
|
cancelRefreshJob();
|
||||||
|
}
|
||||||
|
// update the status only if it's changed
|
||||||
|
ThingStatusInfo statusInfo = ThingStatusInfoBuilder.create(status, statusDetail).withDescription(description)
|
||||||
|
.build();
|
||||||
|
if (!statusInfo.equals(getThing().getStatusInfo())) {
|
||||||
|
super.updateStatus(status, statusDetail, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
cancelRefreshJob();
|
||||||
|
var routeros = this.routeros;
|
||||||
|
if (routeros != null) {
|
||||||
|
routeros.stop();
|
||||||
|
this.routeros = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleRefreshJob() {
|
||||||
|
synchronized (this) {
|
||||||
|
var cfg = this.config;
|
||||||
|
if (refreshJob == null) {
|
||||||
|
int refreshPeriod = 10;
|
||||||
|
if (cfg != null) {
|
||||||
|
refreshPeriod = cfg.refresh;
|
||||||
|
} else {
|
||||||
|
logger.warn("null config spotted in scheduleRefreshJob");
|
||||||
|
}
|
||||||
|
logger.debug("Scheduling refresh job every {}s", refreshPeriod);
|
||||||
|
refreshJob = scheduler.scheduleWithFixedDelay(this::scheduledRun, 0, refreshPeriod, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelRefreshJob() {
|
||||||
|
synchronized (this) {
|
||||||
|
var job = this.refreshJob;
|
||||||
|
if (job != null) {
|
||||||
|
logger.debug("Cancelling refresh job");
|
||||||
|
job.cancel(true);
|
||||||
|
this.refreshJob = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduledRun() {
|
||||||
|
var routeros = this.routeros;
|
||||||
|
if (routeros == null) {
|
||||||
|
logger.error("RouterOS device is null in scheduledRun");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!routeros.isConnected()) {
|
||||||
|
// Perform connection
|
||||||
|
try {
|
||||||
|
logger.debug("Starting routeros model");
|
||||||
|
routeros.start();
|
||||||
|
|
||||||
|
RouterosRouterboardInfo rbInfo = routeros.getRouterboardInfo();
|
||||||
|
if (rbInfo != null) {
|
||||||
|
Map<String, String> bridgeProps = editProperties();
|
||||||
|
bridgeProps.put(MikrotikBindingConstants.PROPERTY_MODEL, rbInfo.getModel());
|
||||||
|
bridgeProps.put(MikrotikBindingConstants.PROPERTY_FIRMWARE, rbInfo.getFirmware());
|
||||||
|
bridgeProps.put(MikrotikBindingConstants.PROPERTY_SERIAL_NUMBER, rbInfo.getSerialNumber());
|
||||||
|
updateProperties(bridgeProps);
|
||||||
|
} else {
|
||||||
|
logger.warn("Failed to set RouterBOARD properties for bridge {}", getThing().getUID());
|
||||||
|
}
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
} catch (MikrotikApiException e) {
|
||||||
|
logger.warn("Error while logging in to RouterOS {} | Cause: {}", getThing().getUID(), e, e.getCause());
|
||||||
|
|
||||||
|
String errorMessage = e.getMessage();
|
||||||
|
if (errorMessage == null) {
|
||||||
|
errorMessage = "Error connecting (UNKNOWN ERROR)";
|
||||||
|
}
|
||||||
|
if (errorMessage.contains("Command timed out") || errorMessage.contains("Error connecting")) {
|
||||||
|
routeros.stop();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorMessage);
|
||||||
|
} else if (errorMessage.contains("Connection refused")) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
|
"Remote host refused to connect, make sure port is correct");
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We're connected - do a usual polling cycle
|
||||||
|
performRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performRefresh() {
|
||||||
|
var routeros = this.routeros;
|
||||||
|
if (routeros == null) {
|
||||||
|
logger.error("RouterOS device is null in performRefresh");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
logger.debug("Refreshing RouterOS caches for {}", getThing().getUID());
|
||||||
|
routeros.refresh();
|
||||||
|
// refresh own channels
|
||||||
|
for (Channel channel : getThing().getChannels()) {
|
||||||
|
try {
|
||||||
|
refreshChannel(channel.getUID());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
throw new ChannelUpdateException(getThing().getUID(), channel.getUID(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// refresh all the client things below
|
||||||
|
getThing().getThings().forEach(thing -> {
|
||||||
|
ThingHandler handler = thing.getHandler();
|
||||||
|
if (handler instanceof MikrotikBaseThingHandler<?>) {
|
||||||
|
((MikrotikBaseThingHandler<?>) handler).refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (ChannelUpdateException e) {
|
||||||
|
logger.debug("Error updating channel! {}", e.getMessage(), e.getCause());
|
||||||
|
} catch (MikrotikApiException e) {
|
||||||
|
logger.error("RouterOS cache refresh failed in {} due to Mikrotik API error", getThing().getUID(), e);
|
||||||
|
routeros.stop();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Unhandled exception while refreshing the {} RouterOS model", getThing().getUID(), e);
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
logger.debug("Handling command = {} for channel = {}", command, channelUID);
|
||||||
|
if (getThing().getStatus() == ONLINE) {
|
||||||
|
RouterosDevice routeros = getRouteros();
|
||||||
|
if (routeros != null) {
|
||||||
|
if (command == REFRESH) {
|
||||||
|
refreshChannel(channelUID);
|
||||||
|
} else {
|
||||||
|
logger.warn("Ignoring command = {} for channel = {} as it is not yet supported", command,
|
||||||
|
channelUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void refreshChannel(ChannelUID channelUID) {
|
||||||
|
RouterosDevice routerOs = getRouteros();
|
||||||
|
String channelID = channelUID.getIdWithoutGroup();
|
||||||
|
RouterosSystemResources rbRes = null;
|
||||||
|
if (routerOs != null) {
|
||||||
|
rbRes = routerOs.getSysResources();
|
||||||
|
}
|
||||||
|
State oldState = currentState.getOrDefault(channelID, UnDefType.NULL);
|
||||||
|
State newState = oldState;
|
||||||
|
|
||||||
|
if (rbRes == null) {
|
||||||
|
newState = UnDefType.NULL;
|
||||||
|
} else {
|
||||||
|
switch (channelID) {
|
||||||
|
case MikrotikBindingConstants.CHANNEL_UP_SINCE:
|
||||||
|
newState = StateUtil.timeOrNull(rbRes.getUptimeStart());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_FREE_SPACE:
|
||||||
|
newState = StateUtil.qtyBytesOrNull(rbRes.getFreeSpace());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TOTAL_SPACE:
|
||||||
|
newState = StateUtil.qtyBytesOrNull(rbRes.getTotalSpace());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_USED_SPACE:
|
||||||
|
newState = StateUtil.qtyPercentOrNull(rbRes.getSpaceUse());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_FREE_MEM:
|
||||||
|
newState = StateUtil.qtyBytesOrNull(rbRes.getFreeMem());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_TOTAL_MEM:
|
||||||
|
newState = StateUtil.qtyBytesOrNull(rbRes.getTotalMem());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_USED_MEM:
|
||||||
|
newState = StateUtil.qtyPercentOrNull(rbRes.getMemUse());
|
||||||
|
break;
|
||||||
|
case MikrotikBindingConstants.CHANNEL_CPU_LOAD:
|
||||||
|
newState = StateUtil.qtyPercentOrNull(rbRes.getCpuLoad());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newState.equals(oldState)) {
|
||||||
|
updateState(channelID, newState);
|
||||||
|
currentState.put(channelID, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,239 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.mikrotik.internal.MikrotikBindingConstants.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.MikrotikBindingConstants;
|
||||||
|
import org.openhab.binding.mikrotik.internal.config.WirelessClientThingConfig;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosCapsmanRegistration;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosDevice;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosRegistrationBase;
|
||||||
|
import org.openhab.binding.mikrotik.internal.model.RouterosWirelessRegistration;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.RateCalculator;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.StateUtil;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MikrotikWirelessClientThingHandler} is a {@link MikrotikBaseThingHandler} subclass that wraps shared
|
||||||
|
* functionality for all wireless clients listed either in CAPsMAN or Wireless RouterOS sections.
|
||||||
|
* It is responsible for handling commands, which are sent to one of the channels and emit channel updates whenever
|
||||||
|
* required.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class MikrotikWirelessClientThingHandler extends MikrotikBaseThingHandler<WirelessClientThingConfig> {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(MikrotikWirelessClientThingHandler.class);
|
||||||
|
|
||||||
|
private @Nullable RouterosRegistrationBase wifiReg;
|
||||||
|
|
||||||
|
private boolean online = false;
|
||||||
|
private boolean continuousConnection = false;
|
||||||
|
private @Nullable LocalDateTime lastSeen;
|
||||||
|
|
||||||
|
private final RateCalculator txByteRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator rxByteRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator txPacketRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
private final RateCalculator rxPacketRate = new RateCalculator(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
public static boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return MikrotikBindingConstants.THING_TYPE_WIRELESS_CLIENT.equals(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MikrotikWirelessClientThingHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean fetchModels() {
|
||||||
|
var cfg = this.config;
|
||||||
|
if (cfg != null) {
|
||||||
|
RouterosDevice routeros = getRouterOs();
|
||||||
|
|
||||||
|
RouterosWirelessRegistration wifiRegistration = null;
|
||||||
|
if (routeros != null) {
|
||||||
|
wifiRegistration = routeros.findWirelessRegistration(cfg.mac);
|
||||||
|
}
|
||||||
|
this.wifiReg = wifiRegistration;
|
||||||
|
if (wifiRegistration != null && !cfg.ssid.isBlank()
|
||||||
|
&& !cfg.ssid.equalsIgnoreCase(wifiRegistration.getSSID())) {
|
||||||
|
this.wifiReg = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.wifiReg == null && routeros != null) {
|
||||||
|
// try looking in capsman when there is no wirelessRegistration
|
||||||
|
RouterosCapsmanRegistration capsmanReg = routeros.findCapsmanRegistration(cfg.mac);
|
||||||
|
this.wifiReg = capsmanReg;
|
||||||
|
if (capsmanReg != null && !cfg.ssid.isBlank() && !cfg.ssid.equalsIgnoreCase(capsmanReg.getSSID())) {
|
||||||
|
this.wifiReg = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.wifiReg != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshModels() {
|
||||||
|
this.online = fetchModels();
|
||||||
|
if (online) {
|
||||||
|
lastSeen = LocalDateTime.now();
|
||||||
|
} else {
|
||||||
|
continuousConnection = false;
|
||||||
|
}
|
||||||
|
var wifiReg = this.wifiReg;
|
||||||
|
if (wifiReg != null) {
|
||||||
|
var cfg = this.config;
|
||||||
|
int considerContinuous = 180;
|
||||||
|
if (cfg != null) {
|
||||||
|
considerContinuous = cfg.considerContinuous;
|
||||||
|
}
|
||||||
|
txByteRate.update(wifiReg.getTxBytes());
|
||||||
|
rxByteRate.update(wifiReg.getRxBytes());
|
||||||
|
txPacketRate.update(wifiReg.getTxPackets());
|
||||||
|
rxPacketRate.update(wifiReg.getRxPackets());
|
||||||
|
LocalDateTime uptimeStart = wifiReg.getUptimeStart();
|
||||||
|
continuousConnection = (uptimeStart != null)
|
||||||
|
&& LocalDateTime.now().isAfter(uptimeStart.plusSeconds(considerContinuous));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void refreshChannel(ChannelUID channelUID) {
|
||||||
|
var wifiReg = this.wifiReg;
|
||||||
|
if (wifiReg == null) {
|
||||||
|
logger.warn("wifiReg is null in refreshChannel({})", channelUID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String channelID = channelUID.getIdWithoutGroup();
|
||||||
|
State oldState = currentState.getOrDefault(channelID, UnDefType.NULL);
|
||||||
|
State newState = oldState;
|
||||||
|
|
||||||
|
if (channelID.equals(CHANNEL_CONNECTED)) {
|
||||||
|
newState = StateUtil.boolOrNull(online);
|
||||||
|
} else if (channelID.equals(CHANNEL_LAST_SEEN)) {
|
||||||
|
newState = StateUtil.timeOrNull(lastSeen);
|
||||||
|
} else if (channelID.equals(CHANNEL_CONTINUOUS)) {
|
||||||
|
newState = StateUtil.boolOrNull(continuousConnection);
|
||||||
|
} else if (!online) {
|
||||||
|
newState = UnDefType.NULL;
|
||||||
|
} else {
|
||||||
|
switch (channelID) {
|
||||||
|
case CHANNEL_NAME:
|
||||||
|
newState = StateUtil.stringOrNull(wifiReg.getName());
|
||||||
|
break;
|
||||||
|
case CHANNEL_COMMENT:
|
||||||
|
newState = StateUtil.stringOrNull(wifiReg.getComment());
|
||||||
|
break;
|
||||||
|
case CHANNEL_MAC:
|
||||||
|
newState = StateUtil.stringOrNull(wifiReg.getMacAddress());
|
||||||
|
break;
|
||||||
|
case CHANNEL_INTERFACE:
|
||||||
|
newState = StateUtil.stringOrNull(wifiReg.getInterfaceName());
|
||||||
|
break;
|
||||||
|
case CHANNEL_SSID:
|
||||||
|
newState = StateUtil.stringOrNull(wifiReg.getSSID());
|
||||||
|
break;
|
||||||
|
case CHANNEL_UP_SINCE:
|
||||||
|
newState = StateUtil.timeOrNull(wifiReg.getUptimeStart());
|
||||||
|
break;
|
||||||
|
case CHANNEL_TX_DATA_RATE:
|
||||||
|
newState = StateUtil.qtyMegabitPerSecOrNull(txByteRate.getMegabitRate());
|
||||||
|
break;
|
||||||
|
case CHANNEL_RX_DATA_RATE:
|
||||||
|
newState = StateUtil.qtyMegabitPerSecOrNull(rxByteRate.getMegabitRate());
|
||||||
|
break;
|
||||||
|
case CHANNEL_TX_PACKET_RATE:
|
||||||
|
newState = StateUtil.floatOrNull(txPacketRate.getRate());
|
||||||
|
break;
|
||||||
|
case CHANNEL_RX_PACKET_RATE:
|
||||||
|
newState = StateUtil.floatOrNull(rxPacketRate.getRate());
|
||||||
|
break;
|
||||||
|
case CHANNEL_TX_BYTES:
|
||||||
|
newState = StateUtil.bigIntOrNull(wifiReg.getTxBytes());
|
||||||
|
break;
|
||||||
|
case CHANNEL_RX_BYTES:
|
||||||
|
newState = StateUtil.bigIntOrNull(wifiReg.getRxBytes());
|
||||||
|
break;
|
||||||
|
case CHANNEL_TX_PACKETS:
|
||||||
|
newState = StateUtil.bigIntOrNull(wifiReg.getTxPackets());
|
||||||
|
break;
|
||||||
|
case CHANNEL_RX_PACKETS:
|
||||||
|
newState = StateUtil.bigIntOrNull(wifiReg.getRxPackets());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newState = UnDefType.NULL;
|
||||||
|
if (wifiReg instanceof RouterosWirelessRegistration) {
|
||||||
|
newState = getWirelessRegistrationChannelState(channelID);
|
||||||
|
} else if (wifiReg instanceof RouterosCapsmanRegistration) {
|
||||||
|
newState = getCapsmanRegistrationChannelState(channelID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newState.equals(oldState)) {
|
||||||
|
updateState(channelID, newState);
|
||||||
|
currentState.put(channelID, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
protected State getCapsmanRegistrationChannelState(String channelID) {
|
||||||
|
if (this.wifiReg == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
RouterosCapsmanRegistration capsmanReg = (RouterosCapsmanRegistration) this.wifiReg;
|
||||||
|
switch (channelID) {
|
||||||
|
case CHANNEL_SIGNAL:
|
||||||
|
return StateUtil.intOrNull(capsmanReg.getRxSignal());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
protected State getWirelessRegistrationChannelState(String channelID) {
|
||||||
|
if (this.wifiReg == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
RouterosWirelessRegistration wirelessReg = (RouterosWirelessRegistration) this.wifiReg;
|
||||||
|
switch (channelID) {
|
||||||
|
case CHANNEL_SIGNAL:
|
||||||
|
return StateUtil.intOrNull(wirelessReg.getRxSignal());
|
||||||
|
default:
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeCommand(ChannelUID channelUID, Command command) {
|
||||||
|
if (!online) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.warn("Ignoring unsupported command = {} for channel = {}", command, channelUID);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosBaseData} is a base class for other data models having internal hashmap access methods and
|
||||||
|
* values convertors.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public abstract class RouterosBaseData {
|
||||||
|
private final Map<String, String> propMap;
|
||||||
|
|
||||||
|
public RouterosBaseData(Map<String, String> props) {
|
||||||
|
this.propMap = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mergeProps(Map<String, String> otherProps) {
|
||||||
|
this.propMap.putAll(otherProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean hasProp(String key) {
|
||||||
|
return propMap.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getProp(String key, String defaultValue) {
|
||||||
|
return propMap.getOrDefault(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setProp(String key, String value) {
|
||||||
|
propMap.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable String getProp(String key) {
|
||||||
|
return propMap.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable Integer getIntProp(String key) {
|
||||||
|
String val = propMap.get(key);
|
||||||
|
return val == null ? null : Integer.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable BigInteger getBigIntProp(String key) {
|
||||||
|
String val = propMap.get(key);
|
||||||
|
return val == null ? null : new BigInteger(propMap.getOrDefault(key, "0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable Float getFloatProp(String key) {
|
||||||
|
String val = propMap.get(key);
|
||||||
|
return val == null ? null : Float.valueOf(val);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosBridgeInterface} is a model class for `bridge` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosBridgeInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosBridgeInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.BRIDGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosCapInterface} is a model class for `cap` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosCapInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosCapInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.CAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMaster() {
|
||||||
|
return getProp("slave", "").equals("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDynamic() {
|
||||||
|
return getProp("dynamic", "").equals("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBound() {
|
||||||
|
return getProp("bound", "").equals("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return getProp("inactive", "").equals("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getCurrentState() {
|
||||||
|
return getProp("current-state");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getRateSet() {
|
||||||
|
return getProp("current-basic-rate-set");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getRegisteredClients() {
|
||||||
|
return getIntProp("current-registered-clients");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getAuthorizedClients() {
|
||||||
|
return getIntProp("current-authorized-clients");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosCapsmanRegistration} is a model class for WiFi client data retrieced from CAPsMAN controller
|
||||||
|
* in RouterOS. Is a subclass of {@link RouterosRegistrationBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosCapsmanRegistration extends RouterosRegistrationBase {
|
||||||
|
public RouterosCapsmanRegistration(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getIdentity() {
|
||||||
|
return getProp("eap-identity");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getRxSignal() {
|
||||||
|
return getIntProp("rx-signal");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,301 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import me.legrange.mikrotik.ApiConnection;
|
||||||
|
import me.legrange.mikrotik.ApiConnectionException;
|
||||||
|
import me.legrange.mikrotik.MikrotikApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosDevice} class is wrapped inside a bridge thing and responsible for communication with
|
||||||
|
* Mikrotik device, data fetching, caching and aggregation.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosDevice {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(RouterosDevice.class);
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
private final int connectionTimeout;
|
||||||
|
private final String login;
|
||||||
|
private final String password;
|
||||||
|
private @Nullable ApiConnection connection;
|
||||||
|
|
||||||
|
public static final String PROP_ID_KEY = ".id";
|
||||||
|
public static final String PROP_TYPE_KEY = "type";
|
||||||
|
public static final String PROP_NAME_KEY = "name";
|
||||||
|
public static final String PROP_SSID_KEY = "ssid";
|
||||||
|
|
||||||
|
private static final String CMD_PRINT_IFACES = "/interface/print";
|
||||||
|
private static final String CMD_PRINT_IFACE_TYPE_TPL = "/interface/%s/print";
|
||||||
|
private static final String CMD_MONTOR_IFACE_MONITOR_TPL = "/interface/%s/monitor numbers=%s once";
|
||||||
|
private static final String CMD_PRINT_CAPS_IFACES = "/caps-man/interface/print";
|
||||||
|
private static final String CMD_PRINT_CAPSMAN_REGS = "/caps-man/registration-table/print";
|
||||||
|
private static final String CMD_PRINT_WIRELESS_REGS = "/interface/wireless/registration-table/print";
|
||||||
|
private static final String CMD_PRINT_RESOURCE = "/system/resource/print";
|
||||||
|
private static final String CMD_PRINT_RB_INFO = "/system/routerboard/print";
|
||||||
|
|
||||||
|
private final List<RouterosInterfaceBase> interfaceCache = new ArrayList<>();
|
||||||
|
private final List<RouterosCapsmanRegistration> capsmanRegistrationCache = new ArrayList<>();
|
||||||
|
private final List<RouterosWirelessRegistration> wirelessRegistrationCache = new ArrayList<>();
|
||||||
|
private final Set<String> monitoredInterfaces = new HashSet<>();
|
||||||
|
private final Map<String, String> wlanSsid = new HashMap<>();
|
||||||
|
|
||||||
|
private @Nullable RouterosSystemResources resourcesCache;
|
||||||
|
private @Nullable RouterosRouterboardInfo rbInfo;
|
||||||
|
|
||||||
|
private static Optional<RouterosInterfaceBase> createTypedInterface(Map<String, String> interfaceProps) {
|
||||||
|
RouterosInterfaceType ifaceType = RouterosInterfaceType.resolve(interfaceProps.get(PROP_TYPE_KEY));
|
||||||
|
if (ifaceType == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
switch (ifaceType) {
|
||||||
|
case ETHERNET:
|
||||||
|
return Optional.of(new RouterosEthernetInterface(interfaceProps));
|
||||||
|
case BRIDGE:
|
||||||
|
return Optional.of(new RouterosBridgeInterface(interfaceProps));
|
||||||
|
case CAP:
|
||||||
|
return Optional.of(new RouterosCapInterface(interfaceProps));
|
||||||
|
case WLAN:
|
||||||
|
return Optional.of(new RouterosWlanInterface(interfaceProps));
|
||||||
|
case PPPOE_CLIENT:
|
||||||
|
return Optional.of(new RouterosPPPoECliInterface(interfaceProps));
|
||||||
|
case L2TP_SERVER:
|
||||||
|
return Optional.of(new RouterosL2TPSrvInterface(interfaceProps));
|
||||||
|
case L2TP_CLIENT:
|
||||||
|
return Optional.of(new RouterosL2TPCliInterface(interfaceProps));
|
||||||
|
default:
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouterosDevice(String host, int port, String login, String password) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.login = login;
|
||||||
|
this.password = password;
|
||||||
|
this.connectionTimeout = ApiConnection.DEFAULT_CONNECTION_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
return conn != null && conn.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws MikrotikApiException {
|
||||||
|
login();
|
||||||
|
updateRouterboardInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn != null && conn.isConnected()) {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void login() throws MikrotikApiException {
|
||||||
|
logger.debug("Attempting login to {} ...", host);
|
||||||
|
ApiConnection conn = ApiConnection.connect(SocketFactory.getDefault(), host, port, connectionTimeout);
|
||||||
|
conn.login(login, password);
|
||||||
|
logger.debug("Logged in to RouterOS at {} !", host);
|
||||||
|
this.connection = conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout() {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
logger.debug("Logging out of {}", host);
|
||||||
|
if (conn != null) {
|
||||||
|
logger.debug("Closing connection to {}", host);
|
||||||
|
try {
|
||||||
|
conn.close();
|
||||||
|
} catch (ApiConnectionException e) {
|
||||||
|
logger.debug("Logout error", e);
|
||||||
|
} finally {
|
||||||
|
this.connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean registerForMonitoring(String interfaceName) {
|
||||||
|
return monitoredInterfaces.add(interfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean unregisterForMonitoring(String interfaceName) {
|
||||||
|
return monitoredInterfaces.remove(interfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() throws MikrotikApiException {
|
||||||
|
synchronized (this) {
|
||||||
|
updateResources();
|
||||||
|
updateInterfaceData();
|
||||||
|
updateCapsmanRegistrations();
|
||||||
|
updateWirelessRegistrations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosRouterboardInfo getRouterboardInfo() {
|
||||||
|
return rbInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosSystemResources getSysResources() {
|
||||||
|
return resourcesCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosCapsmanRegistration findCapsmanRegistration(String macAddress) {
|
||||||
|
Optional<RouterosCapsmanRegistration> searchResult = capsmanRegistrationCache.stream()
|
||||||
|
.filter(registration -> macAddress.equalsIgnoreCase(registration.getMacAddress())).findFirst();
|
||||||
|
return searchResult.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable RouterosWirelessRegistration findWirelessRegistration(String macAddress) {
|
||||||
|
Optional<RouterosWirelessRegistration> searchResult = wirelessRegistrationCache.stream()
|
||||||
|
.filter(registration -> macAddress.equalsIgnoreCase(registration.getMacAddress())).findFirst();
|
||||||
|
return searchResult.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
public @Nullable RouterosInterfaceBase findInterface(String name) {
|
||||||
|
Optional<RouterosInterfaceBase> searchResult = interfaceCache.stream()
|
||||||
|
.filter(iface -> iface.getName() != null && iface.getName().equalsIgnoreCase(name)).findFirst();
|
||||||
|
return searchResult.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
private void updateInterfaceData() throws MikrotikApiException {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, String>> ifaceResponse = conn.execute(CMD_PRINT_IFACES);
|
||||||
|
|
||||||
|
Set<String> interfaceTypesToPoll = new HashSet<>();
|
||||||
|
this.wlanSsid.clear();
|
||||||
|
this.interfaceCache.clear();
|
||||||
|
ifaceResponse.forEach(props -> {
|
||||||
|
Optional<RouterosInterfaceBase> ifaceOpt = createTypedInterface(props);
|
||||||
|
if (ifaceOpt.isPresent()) {
|
||||||
|
RouterosInterfaceBase iface = ifaceOpt.get();
|
||||||
|
if (iface.hasDetailedReport()) {
|
||||||
|
interfaceTypesToPoll.add(iface.getApiType());
|
||||||
|
}
|
||||||
|
this.interfaceCache.add(iface);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, Map<String, String>> typedIfaceResponse = new HashMap<>();
|
||||||
|
for (String ifaceApiType : interfaceTypesToPoll) {
|
||||||
|
String cmd = String.format(CMD_PRINT_IFACE_TYPE_TPL, ifaceApiType);
|
||||||
|
if (ifaceApiType.compareTo("cap") == 0) {
|
||||||
|
cmd = CMD_PRINT_CAPS_IFACES;
|
||||||
|
}
|
||||||
|
connection.execute(cmd).forEach(propMap -> {
|
||||||
|
String ifaceName = propMap.get(PROP_NAME_KEY);
|
||||||
|
if (ifaceName != null) {
|
||||||
|
if (typedIfaceResponse.containsKey(ifaceName)) {
|
||||||
|
typedIfaceResponse.get(ifaceName).putAll(propMap);
|
||||||
|
} else {
|
||||||
|
typedIfaceResponse.put(ifaceName, propMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RouterosInterfaceBase ifaceModel : interfaceCache) {
|
||||||
|
// Enrich with detailed data
|
||||||
|
|
||||||
|
Map<String, String> additionalIfaceProps = typedIfaceResponse.get(ifaceModel.getName());
|
||||||
|
if (additionalIfaceProps != null) {
|
||||||
|
ifaceModel.mergeProps(additionalIfaceProps);
|
||||||
|
}
|
||||||
|
// Get monitor data
|
||||||
|
if (ifaceModel.hasMonitor() && monitoredInterfaces.contains(ifaceModel.getName())) {
|
||||||
|
String cmd = String.format(CMD_MONTOR_IFACE_MONITOR_TPL, ifaceModel.getApiType(), ifaceModel.getName());
|
||||||
|
List<Map<String, String>> monitorProps = connection.execute(cmd);
|
||||||
|
ifaceModel.mergeProps(monitorProps.get(0));
|
||||||
|
}
|
||||||
|
// Note SSIDs for non-CAPsMAN wireless clients
|
||||||
|
String ifaceName = ifaceModel.getName();
|
||||||
|
String ifaceSsid = ifaceModel.getProperty(PROP_SSID_KEY);
|
||||||
|
if (ifaceName != null && ifaceSsid != null && !ifaceName.isBlank() && !ifaceSsid.isBlank()) {
|
||||||
|
this.wlanSsid.put(ifaceName, ifaceSsid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCapsmanRegistrations() throws MikrotikApiException {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Map<String, String>> response = conn.execute(CMD_PRINT_CAPSMAN_REGS);
|
||||||
|
if (response != null) {
|
||||||
|
capsmanRegistrationCache.clear();
|
||||||
|
response.forEach(reg -> capsmanRegistrationCache.add(new RouterosCapsmanRegistration(reg)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWirelessRegistrations() throws MikrotikApiException {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Map<String, String>> response = conn.execute(CMD_PRINT_WIRELESS_REGS);
|
||||||
|
wirelessRegistrationCache.clear();
|
||||||
|
response.forEach(props -> {
|
||||||
|
String wlanIfaceName = props.get("interface");
|
||||||
|
String wlanSsidName = wlanSsid.get(wlanIfaceName);
|
||||||
|
|
||||||
|
if (wlanSsidName != null && wlanIfaceName != null && !wlanIfaceName.isBlank() && !wlanSsidName.isBlank()) {
|
||||||
|
props.put(PROP_SSID_KEY, wlanSsidName);
|
||||||
|
}
|
||||||
|
wirelessRegistrationCache.add(new RouterosWirelessRegistration(props));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateResources() throws MikrotikApiException {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Map<String, String>> response = conn.execute(CMD_PRINT_RESOURCE);
|
||||||
|
this.resourcesCache = new RouterosSystemResources(response.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRouterboardInfo() throws MikrotikApiException {
|
||||||
|
ApiConnection conn = this.connection;
|
||||||
|
if (conn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Map<String, String>> response = conn.execute(CMD_PRINT_RB_INFO);
|
||||||
|
this.rbInfo = new RouterosRouterboardInfo(response.get(0));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosEthernetInterface} is a model class for `ether` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosEthernetInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosEthernetInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.ETHERNET;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiType() {
|
||||||
|
return "ethernet";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
// PowerLine interfaces are of ehter type too
|
||||||
|
String name = getDefaultName();
|
||||||
|
return name != null && !name.startsWith("pwr");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getDefaultName() {
|
||||||
|
return getProp("default-name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getRate() {
|
||||||
|
return getProp("rate");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getState() {
|
||||||
|
return getProp("status");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import static org.openhab.binding.mikrotik.internal.model.RouterosDevice.PROP_ID_KEY;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosInterfaceBase} is a base model class for network interface models having casting accessors for
|
||||||
|
* data that is same for all interface types.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public abstract class RouterosInterfaceBase extends RouterosBaseData {
|
||||||
|
protected @Nullable RouterosInterfaceType type;
|
||||||
|
|
||||||
|
public RouterosInterfaceBase(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
this.type = RouterosInterfaceType.resolve(getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getProperty(String propName) {
|
||||||
|
return getProp(propName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract RouterosInterfaceType getDesignedType();
|
||||||
|
|
||||||
|
public abstract boolean hasDetailedReport();
|
||||||
|
|
||||||
|
public abstract boolean hasMonitor();
|
||||||
|
|
||||||
|
public String getApiType() {
|
||||||
|
return getDesignedType().toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
public boolean validate() {
|
||||||
|
return getDesignedType() == this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getId() {
|
||||||
|
return getProp(PROP_ID_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getType() {
|
||||||
|
return getProp("type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getName() {
|
||||||
|
return getProp("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getComment() {
|
||||||
|
return getProp("comment");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getMacAddress() {
|
||||||
|
return getProp("mac-address");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return getProp("disabled", "").equals("false");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return getProp("running", "").equals("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getLinkDowns() {
|
||||||
|
return getIntProp("link-downs");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getLastLinkDownTime() {
|
||||||
|
return Converter.fromRouterosTime(getProp("last-link-down-time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getLastLinkUpTime() {
|
||||||
|
return Converter.fromRouterosTime(getProp("last-link-up-time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxBytes() {
|
||||||
|
return getBigIntProp("tx-byte");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxBytes() {
|
||||||
|
return getBigIntProp("rx-byte");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxPackets() {
|
||||||
|
return getBigIntProp("tx-packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxPackets() {
|
||||||
|
return getBigIntProp("rx-packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxDrops() {
|
||||||
|
return getBigIntProp("tx-drop");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxDrops() {
|
||||||
|
return getBigIntProp("rx-drop");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxErrors() {
|
||||||
|
return getBigIntProp("tx-error");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxErrors() {
|
||||||
|
return getBigIntProp("rx-error");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosInterfaceType} enum wraps RouterOS network interface type strings.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NonNullByDefault
|
||||||
|
public enum RouterosInterfaceType {
|
||||||
|
ETHERNET("ether"),
|
||||||
|
BRIDGE("bridge"),
|
||||||
|
WLAN("wlan"),
|
||||||
|
CAP("cap"),
|
||||||
|
PPPOE_CLIENT("pppoe-out"),
|
||||||
|
L2TP_SERVER("l2tp-in"),
|
||||||
|
L2TP_CLIENT("l2tp-out");
|
||||||
|
|
||||||
|
private final String typeName;
|
||||||
|
|
||||||
|
RouterosInterfaceType(String routerosType) {
|
||||||
|
this.typeName = routerosType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalsName(String otherType) {
|
||||||
|
// (otherName == null) check is not needed because name.equals(null) returns false
|
||||||
|
return typeName.equals(otherType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return this.typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable static RouterosInterfaceType resolve(@Nullable String routerosType) {
|
||||||
|
for (RouterosInterfaceType current : RouterosInterfaceType.values()) {
|
||||||
|
if (current.typeName.equals(routerosType)) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosL2TPCliInterface} is a model class for `l2tp-out` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosL2TPCliInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosL2TPCliInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.L2TP_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiType() {
|
||||||
|
return "l2tp-client";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getStatus() {
|
||||||
|
return getProp("status");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getEncoding() {
|
||||||
|
return String.format("Encoding: %s", getProp("encoding", "None"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getServerAddress() {
|
||||||
|
return getProp("connect-to");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getLocalAddress() {
|
||||||
|
return getProp("local-address");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getRemoteAddress() {
|
||||||
|
return getProp("remote-address");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getUptime() {
|
||||||
|
return getProp("uptime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getUptimeStart() {
|
||||||
|
return Converter.routerosPeriodBack(getUptime());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosL2TPSrvInterface} is a model class for `l2tp-in` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosL2TPSrvInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosL2TPSrvInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.L2TP_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiType() {
|
||||||
|
return "l2tp-server";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getStatus() {
|
||||||
|
return getProp("status");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getEncoding() {
|
||||||
|
return String.format("Encoding: %s", getProp("encoding", "None"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getClientAddress() {
|
||||||
|
return getProp("client-address");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getUptime() {
|
||||||
|
return getProp("uptime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getUptimeStart() {
|
||||||
|
return Converter.routerosPeriodBack(getUptime());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosPPPoECliInterface} is a model class for `pppoe-out` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosPPPoECliInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosPPPoECliInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.PPPOE_CLIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiType() {
|
||||||
|
return "pppoe-client";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getMacAddress() {
|
||||||
|
return getProp("ac-mac");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getStatus() {
|
||||||
|
return getProp("status");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getUptime() {
|
||||||
|
return getProp("uptime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getUptimeStart() {
|
||||||
|
return Converter.routerosPeriodBack(getUptime());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import static org.openhab.binding.mikrotik.internal.model.RouterosDevice.PROP_ID_KEY;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosRegistrationBase} is a base model class for WiFi client models having casting accessors for
|
||||||
|
* data that is same for all WiFi client types.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosRegistrationBase extends RouterosBaseData {
|
||||||
|
|
||||||
|
public RouterosRegistrationBase(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
this.postProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void postProcess() {
|
||||||
|
if (hasProp("bytes")) {
|
||||||
|
String bytesStr = getProp("bytes");
|
||||||
|
if (bytesStr != null) {
|
||||||
|
String[] bytes = bytesStr.split(",");
|
||||||
|
setProp("tx-byte", bytes[0]);
|
||||||
|
setProp("rx-byte", bytes[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasProp("packets")) {
|
||||||
|
String packetsStr = getProp("packets");
|
||||||
|
if (packetsStr != null) {
|
||||||
|
String[] packets = packetsStr.split(",");
|
||||||
|
setProp("tx-packet", packets[0]);
|
||||||
|
setProp("rx-packet", packets[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getId() {
|
||||||
|
return getProp(PROP_ID_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getName() {
|
||||||
|
return getProp("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getComment() {
|
||||||
|
return getProp("comment");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getMacAddress() {
|
||||||
|
return getProp("mac-address");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getSSID() {
|
||||||
|
return getProp("ssid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getInterfaceName() {
|
||||||
|
return getProp("interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxBytes() {
|
||||||
|
return getBigIntProp("tx-byte");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxBytes() {
|
||||||
|
return getBigIntProp("rx-byte");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getTxPackets() {
|
||||||
|
return getBigIntProp("tx-packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable BigInteger getRxPackets() {
|
||||||
|
return getBigIntProp("rx-packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getUptime() {
|
||||||
|
return getProp("uptime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getUptimeStart() {
|
||||||
|
return Converter.routerosPeriodBack(getUptime());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosRouterboardInfo} is a model class for RouterOS system info used as bridge thing property values.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosRouterboardInfo extends RouterosBaseData {
|
||||||
|
|
||||||
|
public RouterosRouterboardInfo(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirmware() {
|
||||||
|
return String.format("v%s (%s)", getFirmwareVersion(), getFirmwareType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRouterboard() {
|
||||||
|
return getProp("routerboard", "").equals("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModel() {
|
||||||
|
return getProp("model", "Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSerialNumber() {
|
||||||
|
return getProp("serial-number", "XXX");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirmwareType() {
|
||||||
|
return getProp("firmware-type", "N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirmwareVersion() {
|
||||||
|
return getProp("current-firmware", "Unknown");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosSystemResources} is a model class for RouterOS system info having casting accessors for
|
||||||
|
* data that is available through bridge thing channels.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosSystemResources extends RouterosBaseData {
|
||||||
|
|
||||||
|
public RouterosSystemResources(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getFreeSpace() {
|
||||||
|
return getIntProp("free-hdd-space");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getTotalSpace() {
|
||||||
|
return getIntProp("total-hdd-space");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getSpaceUse() {
|
||||||
|
Integer freeSpace = getFreeSpace(), totalSpace = getTotalSpace();
|
||||||
|
if (freeSpace == null || totalSpace == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return 100 - Math.round(100F * freeSpace / totalSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getFreeMem() {
|
||||||
|
return getIntProp("free-memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getTotalMem() {
|
||||||
|
return getIntProp("total-memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getMemUse() {
|
||||||
|
Integer freeMem = getFreeMem(), totalMem = getTotalMem();
|
||||||
|
if (freeMem == null || totalMem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return 100 - Math.round(100F * freeMem / totalMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getCpuLoad() {
|
||||||
|
return getIntProp("cpu-load");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getUptime() {
|
||||||
|
return getProp("uptime");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getUptimeStart() {
|
||||||
|
return Converter.routerosPeriodBack(getUptime());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.mikrotik.internal.util.Converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosWirelessRegistration} is a model class for WiFi client data retrieced from RouterOS
|
||||||
|
* physical wireless interface. Is a subclass of {@link RouterosRegistrationBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosWirelessRegistration extends RouterosRegistrationBase {
|
||||||
|
public RouterosWirelessRegistration(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRxSignal() {
|
||||||
|
String signalValue = getProp("signal-strength", "0@hz").split("@")[0];
|
||||||
|
return Integer.parseInt(signalValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable LocalDateTime getLastActivity() {
|
||||||
|
return Converter.routerosPeriodBack(getProp("last-activity"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RouterosWlanInterface} is a model class for `waln` interface models having casting accessors for
|
||||||
|
* data that is specific to this network interface kind. Is a subclass of {@link RouterosInterfaceBase}.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RouterosWlanInterface extends RouterosInterfaceBase {
|
||||||
|
public RouterosWlanInterface(Map<String, String> props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouterosInterfaceType getDesignedType() {
|
||||||
|
return RouterosInterfaceType.WLAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApiType() {
|
||||||
|
return "wireless";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDetailedReport() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMonitor() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMaster() {
|
||||||
|
return !getProp("master-interface", "").isBlank();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getCurrentState() {
|
||||||
|
return getProp("status");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getSSID() {
|
||||||
|
return getProp("ssid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getMode() {
|
||||||
|
return getProp("mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getRate() {
|
||||||
|
return getProp("band");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String getInterfaceType() {
|
||||||
|
return getProp("interface-type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRegisteredClients() {
|
||||||
|
Integer registeredClients = getIntProp("registered-clients");
|
||||||
|
return registeredClients == null ? 0 : registeredClients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAuthorizedClients() {
|
||||||
|
Integer authedClients = getIntProp("authenticated-clients");
|
||||||
|
return authedClients == null ? 0 : authedClients;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.util;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoField;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Converter} is a utility class having functions to convert RouterOS-specific data representation strings
|
||||||
|
* to regular Java types.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class Converter {
|
||||||
|
private static final DateTimeFormatter ROUTEROS_FORMAT = DateTimeFormatter.ofPattern("MMM/dd/yyyy kk:mm:ss",
|
||||||
|
Locale.ENGLISH);
|
||||||
|
|
||||||
|
private static final Pattern PERIOD_PATTERN = Pattern.compile("(\\d+)([a-z]+){1,3}");
|
||||||
|
|
||||||
|
public @Nullable static LocalDateTime fromRouterosTime(@Nullable String dateTimeString) {
|
||||||
|
if (dateTimeString == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String fixedTs = dateTimeString.substring(0, 1).toUpperCase() + dateTimeString.substring(1);
|
||||||
|
return LocalDateTime.parse(fixedTs, ROUTEROS_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable static LocalDateTime routerosPeriodBack(@Nullable String durationString) {
|
||||||
|
return routerosPeriodBack(durationString, LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable static LocalDateTime routerosPeriodBack(@Nullable String durationString,
|
||||||
|
LocalDateTime fromDateTime) {
|
||||||
|
if (durationString == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher m = PERIOD_PATTERN.matcher(durationString);
|
||||||
|
LocalDateTime ts = fromDateTime;
|
||||||
|
while (m.find()) {
|
||||||
|
int amount = Integer.parseInt(m.group(1));
|
||||||
|
String periodKey = m.group(2);
|
||||||
|
switch (periodKey) {
|
||||||
|
case "y":
|
||||||
|
ts = ts.minusYears(amount);
|
||||||
|
break;
|
||||||
|
case "w":
|
||||||
|
ts = ts.minusWeeks(amount);
|
||||||
|
break;
|
||||||
|
case "d":
|
||||||
|
ts = ts.minusDays(amount);
|
||||||
|
break;
|
||||||
|
case "h":
|
||||||
|
ts = ts.minusHours(amount);
|
||||||
|
break;
|
||||||
|
case "m":
|
||||||
|
ts = ts.minusMinutes(amount);
|
||||||
|
break;
|
||||||
|
case "s":
|
||||||
|
ts = ts.minusSeconds(amount);
|
||||||
|
break;
|
||||||
|
case "ms":
|
||||||
|
ts = ts.plus(amount, ChronoField.MILLI_OF_SECOND.getBaseUnit());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format("Unable to parse duration %s - %s is unknown", durationString, periodKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.util;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.threeten.extra.Seconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RateCalculator} is used to calculate data changing rate as number per second. Has a separate method
|
||||||
|
* to get megabits per second rate out of byte number.
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class RateCalculator {
|
||||||
|
public static final int BYTES_IN_MEGABIT = 125000;
|
||||||
|
|
||||||
|
private BigDecimal value;
|
||||||
|
float rate;
|
||||||
|
LocalDateTime lastUpdated;
|
||||||
|
|
||||||
|
public RateCalculator(BigDecimal initialValue) {
|
||||||
|
this.value = initialValue;
|
||||||
|
this.lastUpdated = LocalDateTime.now();
|
||||||
|
this.rate = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRate() {
|
||||||
|
return this.rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMegabitRate() {
|
||||||
|
return getRate() / BYTES_IN_MEGABIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(@Nullable BigDecimal currentValue) {
|
||||||
|
if (currentValue != null) {
|
||||||
|
synchronized (this) {
|
||||||
|
LocalDateTime thisUpdated = LocalDateTime.now();
|
||||||
|
Seconds secDiff = Seconds.between(lastUpdated, thisUpdated);
|
||||||
|
this.rate = currentValue.subtract(value).floatValue() / secDiff.getAmount();
|
||||||
|
this.value = currentValue;
|
||||||
|
this.lastUpdated = thisUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(@Nullable BigInteger currentValue) {
|
||||||
|
BigInteger val = currentValue == null ? BigInteger.ZERO : currentValue;
|
||||||
|
this.update(new BigDecimal(val));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.util;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
|
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.OnOffType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link StateUtil} class holds static methods to cast Java native/class types to OpenHAB values
|
||||||
|
*
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class StateUtil {
|
||||||
|
|
||||||
|
public static State stringOrNull(@Nullable String value) {
|
||||||
|
return value == null ? UnDefType.NULL : new StringType(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State qtyMegabitPerSecOrNull(@Nullable Float value) {
|
||||||
|
return value == null ? UnDefType.NULL : new QuantityType<>(value, Units.MEGABIT_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State qtyPercentOrNull(@Nullable Integer value) {
|
||||||
|
return value == null ? UnDefType.NULL : new QuantityType<>(value, Units.PERCENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State qtyBytesOrNull(@Nullable Integer value) {
|
||||||
|
return value == null ? UnDefType.NULL : new QuantityType<>(value, Units.BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State intOrNull(@Nullable Integer value) {
|
||||||
|
return value == null ? UnDefType.NULL : new DecimalType(value.floatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State bigIntOrNull(@Nullable BigInteger value) {
|
||||||
|
return value == null ? UnDefType.NULL : DecimalType.valueOf(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State floatOrNull(@Nullable Float value) {
|
||||||
|
return value == null ? UnDefType.NULL : new DecimalType(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State boolOrNull(@Nullable Boolean value) {
|
||||||
|
if (value == null) {
|
||||||
|
return UnDefType.NULL;
|
||||||
|
}
|
||||||
|
return value ? OnOffType.ON : OnOffType.OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State timeOrNull(@Nullable LocalDateTime value) {
|
||||||
|
return value == null ? UnDefType.NULL : new DateTimeType(value.atZone(ZoneId.systemDefault()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<binding:binding id="mikrotik" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||||
|
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||||
|
|
||||||
|
<name>Mikrotik Binding</name>
|
||||||
|
<description>
|
||||||
|
This is the binding for integrating Mikrotik RouterOS powered devices (routers, access points, switches,
|
||||||
|
etc) to facilitate WiFi clients and network interface tracking.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
</binding:binding>
|
@ -0,0 +1,414 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<thing:thing-descriptions bindingId="mikrotik"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||||
|
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||||
|
|
||||||
|
<bridge-type id="routeros">
|
||||||
|
<label>Mikrotik RouterOS</label>
|
||||||
|
<description>A connection to RouterOS device</description>
|
||||||
|
<channels>
|
||||||
|
<channel id="freeSpace" typeId="freeSpace"/>
|
||||||
|
<channel id="totalSpace" typeId="totalSpace"/>
|
||||||
|
<channel id="usedSpace" typeId="usedSpace"/>
|
||||||
|
<channel id="freeMemory" typeId="freeMemory"/>
|
||||||
|
<channel id="totalMemory" typeId="totalMemory"/>
|
||||||
|
<channel id="usedMemory" typeId="usedMemory"/>
|
||||||
|
<channel id="cpuLoad" typeId="cpuLoad"/>
|
||||||
|
<channel id="upSince" typeId="upSince"/>
|
||||||
|
</channels>
|
||||||
|
<properties>
|
||||||
|
<property name="vendor">Mikrotik</property>
|
||||||
|
<property name="modelId">RouterOS</property>
|
||||||
|
<property name="firmware"/>
|
||||||
|
<property name="serial"/>
|
||||||
|
</properties>
|
||||||
|
<representation-property>name</representation-property>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="host" type="text" required="true">
|
||||||
|
<label>Hostname</label>
|
||||||
|
<description>Hostname or IP address of the RouterOS device</description>
|
||||||
|
<default>192.168.88.1</default>
|
||||||
|
<context>network-address</context>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="port" type="integer" max="65535" min="1" required="false">
|
||||||
|
<label>API Port</label>
|
||||||
|
<description>API Port number of the RouterOS device</description>
|
||||||
|
<default>8728</default>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="login" type="text" required="true">
|
||||||
|
<label>Username</label>
|
||||||
|
<default>admin</default>
|
||||||
|
<description>The username to access the the RouterOS device</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="password" type="text" required="true">
|
||||||
|
<label>Password</label>
|
||||||
|
<description>The user password to access the RouterOS device</description>
|
||||||
|
<context>password</context>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="refresh" type="integer" required="false">
|
||||||
|
<label>Refresh Interval</label>
|
||||||
|
<description>The refresh interval in seconds to poll the RouterOS device</description>
|
||||||
|
<default>10</default>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</bridge-type>
|
||||||
|
|
||||||
|
<thing-type id="interface">
|
||||||
|
<supported-bridge-type-refs>
|
||||||
|
<bridge-type-ref id="routeros"/>
|
||||||
|
</supported-bridge-type-refs>
|
||||||
|
<label>RouterOS Interface</label>
|
||||||
|
<description>A network interface from RouterOS system (ethernet, wifi, vpn, etc.)</description>
|
||||||
|
<channels>
|
||||||
|
<!-- common channels for all interface types -->
|
||||||
|
<channel id="type" typeId="interfaceType"/>
|
||||||
|
<channel id="name" typeId="interfaceName"/>
|
||||||
|
<channel id="comment" typeId="comment"/>
|
||||||
|
<channel id="macAddress" typeId="macAddress"/>
|
||||||
|
<channel id="enabled" typeId="enabled"/>
|
||||||
|
<channel id="connected" typeId="connected"/>
|
||||||
|
<channel id="lastLinkDownTime" typeId="lastLinkDownTime"/>
|
||||||
|
<channel id="lastLinkUpTime" typeId="lastLinkUpTime"/>
|
||||||
|
<channel id="linkDowns" typeId="linkDowns"/>
|
||||||
|
<channel id="txRate" typeId="txRate"/>
|
||||||
|
<channel id="rxRate" typeId="rxRate"/>
|
||||||
|
<channel id="txPacketRate" typeId="txPacketRate"/>
|
||||||
|
<channel id="rxPacketRate" typeId="rxPacketRate"/>
|
||||||
|
<channel id="txBytes" typeId="txBytes"/>
|
||||||
|
<channel id="rxBytes" typeId="rxBytes"/>
|
||||||
|
<channel id="txPackets" typeId="txPackets"/>
|
||||||
|
<channel id="rxPackets" typeId="rxPackets"/>
|
||||||
|
<channel id="txDrops" typeId="txDrops"/>
|
||||||
|
<channel id="rxDrops" typeId="rxDrops"/>
|
||||||
|
<channel id="txErrors" typeId="txErrors"/>
|
||||||
|
<channel id="rxErrors" typeId="rxErrors"/>
|
||||||
|
<!-- ethernet interface channels -->
|
||||||
|
<channel id="defaultName" typeId="defaultName"/>
|
||||||
|
<channel id="rate" typeId="ethernetRate"/>
|
||||||
|
<!-- cap interface channels -->
|
||||||
|
<channel id="state" typeId="state"/>
|
||||||
|
<channel id="registeredClients" typeId="registeredClients"/>
|
||||||
|
<channel id="authorizedClients" typeId="authorizedClients"/>
|
||||||
|
<!-- ppp & vpn interface channels -->
|
||||||
|
<channel id="upSince" typeId="upSince"/>
|
||||||
|
</channels>
|
||||||
|
<representation-property>name</representation-property>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="name" type="text" required="true">
|
||||||
|
<label>Interface Name</label>
|
||||||
|
<description>RouterOS Interface name (i.e. ether1)</description>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</thing-type>
|
||||||
|
|
||||||
|
<thing-type id="wifiRegistration">
|
||||||
|
<supported-bridge-type-refs>
|
||||||
|
<bridge-type-ref id="routeros"/>
|
||||||
|
</supported-bridge-type-refs>
|
||||||
|
<label>RouterOS Wireless Client</label>
|
||||||
|
<description>A wireless client connected to a RouterOS wireless network (direct or CAPsMAN-managed)</description>
|
||||||
|
<channels>
|
||||||
|
<channel id="macAddress" typeId="macAddress"/>
|
||||||
|
<channel id="comment" typeId="comment"/>
|
||||||
|
<channel id="connected" typeId="connected"/>
|
||||||
|
<channel id="continuous" typeId="continuous"/>
|
||||||
|
<channel id="ssid" typeId="ssid"/>
|
||||||
|
<channel id="interface" typeId="interfaceName"/>
|
||||||
|
<channel id="signal" typeId="system.signal-strength"/>
|
||||||
|
<channel id="upSince" typeId="upSince"/>
|
||||||
|
<channel id="lastSeen" typeId="lastSeen"/>
|
||||||
|
<channel id="txRate" typeId="txRate"/>
|
||||||
|
<channel id="rxRate" typeId="rxRate"/>
|
||||||
|
<channel id="txPacketRate" typeId="txPacketRate"/>
|
||||||
|
<channel id="rxPacketRate" typeId="rxPacketRate"/>
|
||||||
|
<channel id="txBytes" typeId="txBytes"/>
|
||||||
|
<channel id="rxBytes" typeId="rxBytes"/>
|
||||||
|
<channel id="txPackets" typeId="txPackets"/>
|
||||||
|
<channel id="rxPackets" typeId="rxPackets"/>
|
||||||
|
</channels>
|
||||||
|
<representation-property>macAddress</representation-property>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="mac" type="text" required="true">
|
||||||
|
<label>Client MAC</label>
|
||||||
|
<description>WiFi client MAC address</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ssid" type="text" required="false">
|
||||||
|
<label>SSID</label>
|
||||||
|
<description>
|
||||||
|
Constraining SSID for the WiFi client (optional). If client will connect to another SSID,
|
||||||
|
this thing
|
||||||
|
will stay offline until client reconnects to specified SSID.
|
||||||
|
</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="considerContinuous" type="integer" required="false">
|
||||||
|
<label>Consider Home Interval</label>
|
||||||
|
<description>The interval in seconds to treat the client as connected permanently</description>
|
||||||
|
<default>180</default>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</thing-type>
|
||||||
|
|
||||||
|
|
||||||
|
<channel-type id="freeSpace" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Free Space</label>
|
||||||
|
<description>Amount of free storage left on device in bytes</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="totalSpace" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Total Space</label>
|
||||||
|
<description>Amount of total storage available on device in bytes</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="usedSpace">
|
||||||
|
<item-type>Number:Dimensionless</item-type>
|
||||||
|
<label>Used Space %</label>
|
||||||
|
<description>Percentage of used device storage space</description>
|
||||||
|
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="freeMemory" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Free RAM</label>
|
||||||
|
<description>Amount of free memory left on device in bytes</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="totalMemory" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Total RAM</label>
|
||||||
|
<description>Amount of total memory available on device in bytes</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="usedMemory">
|
||||||
|
<item-type>Number:Dimensionless</item-type>
|
||||||
|
<label>Used RAM %</label>
|
||||||
|
<description>Percentage of used device memory</description>
|
||||||
|
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="cpuLoad">
|
||||||
|
<item-type>Number:Dimensionless</item-type>
|
||||||
|
<label>CPU Load %</label>
|
||||||
|
<description>CPU load percentage</description>
|
||||||
|
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<channel-type id="interfaceType" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Interface Type</label>
|
||||||
|
<description>Network interface type</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="interfaceName" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Interface Name</label>
|
||||||
|
<description>Network interface name</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="comment" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Comment</label>
|
||||||
|
<description>User-defined comment</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="macAddress" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>MAC Address</label>
|
||||||
|
<description>MAC address of the client or interface</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="enabled">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Enabled</label>
|
||||||
|
<description>Reflects enabled or disabled state</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="connected">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Connected</label>
|
||||||
|
<description>Reflects connected or disconnected state</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="continuous">
|
||||||
|
<item-type>Switch</item-type>
|
||||||
|
<label>Continuous</label>
|
||||||
|
<description>Connection is considered long-running</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="lastLinkDownTime">
|
||||||
|
<item-type>DateTime</item-type>
|
||||||
|
<label>Last Link Down</label>
|
||||||
|
<description>Last time when link went down</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="lastLinkUpTime">
|
||||||
|
<item-type>DateTime</item-type>
|
||||||
|
<label>Last Link Up</label>
|
||||||
|
<description>Last time when link went up</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="linkDowns" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Link Downs</label>
|
||||||
|
<description>Amount of link downs</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txRate">
|
||||||
|
<item-type>Number:DataTransferRate</item-type>
|
||||||
|
<label>Transmission Rate</label>
|
||||||
|
<description>Rate of data transmission in megabits per second</description>
|
||||||
|
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxRate">
|
||||||
|
<item-type>Number:DataTransferRate</item-type>
|
||||||
|
<label>Receiving Rate</label>
|
||||||
|
<description>Rate of data receiving in megabits per second</description>
|
||||||
|
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txPacketRate" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Transmission Packet Rate</label>
|
||||||
|
<description>Rate of data transmission in packets per second</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxPacketRate" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Receiving Packet Rate</label>
|
||||||
|
<description>Rate of data receiving in packets per second</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txBytes" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Transmitted Bytes</label>
|
||||||
|
<description>Amount of bytes transmitted</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxBytes" advanced="true">
|
||||||
|
<item-type>Number:DataAmount</item-type>
|
||||||
|
<label>Received Bytes</label>
|
||||||
|
<description>Amount of bytes received</description>
|
||||||
|
<state readOnly="true" pattern="%d %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txPackets" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Transmitted Packets</label>
|
||||||
|
<description>Amount of packets transmitted</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxPackets" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Received Packets</label>
|
||||||
|
<description>Amount of packets received</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txDrops" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Transmission Drops</label>
|
||||||
|
<description>Amount of packets dropped during transmission</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxDrops" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Receiving Drops</label>
|
||||||
|
<description>Amount of packets dropped during receiving</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="txErrors" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Transmission Errors</label>
|
||||||
|
<description>Amount of errors during transmission</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="rxErrors" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Receiving Errors</label>
|
||||||
|
<description>Amount of errors during receiving</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="defaultName" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Default Name</label>
|
||||||
|
<description>Interface factory name</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="ethernetRate" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Link Rate</label>
|
||||||
|
<description>Ethernet link rate</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="state">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>State</label>
|
||||||
|
<description>WiFi interface state</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="registeredClients">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Registered Clients</label>
|
||||||
|
<description>Amount of clients registered to WiFi interface</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="authorizedClients">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Authorized Clients</label>
|
||||||
|
<description>Amount of clients authorized by WiFi interface</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="upSince">
|
||||||
|
<item-type>DateTime</item-type>
|
||||||
|
<label>Up since</label>
|
||||||
|
<description>Time when thing got up</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="lastSeen">
|
||||||
|
<item-type>DateTime</item-type>
|
||||||
|
<label>Last Seen</label>
|
||||||
|
<description>Time of when the client was last seen connected</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="ssid">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>WiFi Network</label>
|
||||||
|
<description>Wireless Network (SSID) the wireless client is connected to</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
</thing:thing-descriptions>
|
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 Contributors to the openHAB 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.openhab.binding.mikrotik.internal.util;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Oleg Vivtash - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class ConverterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromRouterosTime() {
|
||||||
|
assertThat(Converter.fromRouterosTime("dec/11/2020 20:45:40"),
|
||||||
|
is(equalTo(LocalDateTime.of(2020, 12, 11, 20, 45, 40, 0))));
|
||||||
|
assertThat(Converter.fromRouterosTime("jan/07/2021 09:14:11"),
|
||||||
|
is(equalTo(LocalDateTime.of(2021, 1, 7, 9, 14, 11, 0))));
|
||||||
|
assertThat(Converter.fromRouterosTime("feb/13/2021 23:59:59"),
|
||||||
|
is(equalTo(LocalDateTime.of(2021, 2, 13, 23, 59, 59, 0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromRouterosPeriod() {
|
||||||
|
LocalDateTime fromDateTime = LocalDateTime.of(2021, 2, 1, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("1y3w4d5h6m7s11ms", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2020-01-06T18:53:53.011"))));
|
||||||
|
|
||||||
|
assertNull(Converter.routerosPeriodBack(null));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uptime = 6w6h31m31s
|
||||||
|
* uptime = 3d7h6m43s710ms
|
||||||
|
* uptime = 16h39m58s220ms
|
||||||
|
* uptime = 1h38m53s110ms
|
||||||
|
* uptime = 53m53s950ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("6w6h31m31s", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2020-12-20T17:28:29"))));
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("3d7h6m43s710ms", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2021-01-28T16:53:17.710"))));
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("16h39m58s220ms", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2021-01-31T07:20:02.220"))));
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("1h38m53s110ms", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2021-01-31T22:21:07.110"))));
|
||||||
|
|
||||||
|
assertThat(Converter.routerosPeriodBack("53m53s950ms", fromDateTime),
|
||||||
|
is(equalTo(LocalDateTime.parse("2021-01-31T23:06:07.950"))));
|
||||||
|
}
|
||||||
|
}
|
@ -206,6 +206,7 @@
|
|||||||
<module>org.openhab.binding.mielecloud</module>
|
<module>org.openhab.binding.mielecloud</module>
|
||||||
<module>org.openhab.binding.mihome</module>
|
<module>org.openhab.binding.mihome</module>
|
||||||
<module>org.openhab.binding.miio</module>
|
<module>org.openhab.binding.miio</module>
|
||||||
|
<module>org.openhab.binding.mikrotik</module>
|
||||||
<module>org.openhab.binding.millheat</module>
|
<module>org.openhab.binding.millheat</module>
|
||||||
<module>org.openhab.binding.milight</module>
|
<module>org.openhab.binding.milight</module>
|
||||||
<module>org.openhab.binding.minecraft</module>
|
<module>org.openhab.binding.minecraft</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user