]> git.basschouten.com Git - openhab-addons.git/blob
5ba705ca7b9cae5410aa5d2e2b149c4f3327558f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.freeboxos.internal.handler;
14
15 import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
16 import static org.openhab.core.library.unit.Units.*;
17
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.openhab.binding.freeboxos.internal.action.ServerActions;
27 import org.openhab.binding.freeboxos.internal.api.FreeboxException;
28 import org.openhab.binding.freeboxos.internal.api.rest.AfpManager;
29 import org.openhab.binding.freeboxos.internal.api.rest.AirMediaManager;
30 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager;
31 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager.FtthStatus;
32 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager.Media;
33 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager.Status;
34 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager.SynchroState;
35 import org.openhab.binding.freeboxos.internal.api.rest.ConnectionManager.XdslInfos;
36 import org.openhab.binding.freeboxos.internal.api.rest.FtpManager;
37 import org.openhab.binding.freeboxos.internal.api.rest.LanBrowserManager.Source;
38 import org.openhab.binding.freeboxos.internal.api.rest.LanManager;
39 import org.openhab.binding.freeboxos.internal.api.rest.LanManager.LanConfig;
40 import org.openhab.binding.freeboxos.internal.api.rest.SambaManager;
41 import org.openhab.binding.freeboxos.internal.api.rest.SambaManager.Samba;
42 import org.openhab.binding.freeboxos.internal.api.rest.SystemManager;
43 import org.openhab.binding.freeboxos.internal.api.rest.SystemManager.Config;
44 import org.openhab.binding.freeboxos.internal.api.rest.UPnPAVManager;
45 import org.openhab.binding.freeboxos.internal.api.rest.WifiManager;
46 import org.openhab.core.library.types.QuantityType;
47 import org.openhab.core.library.unit.SIUnits;
48 import org.openhab.core.library.unit.Units;
49 import org.openhab.core.thing.Channel;
50 import org.openhab.core.thing.ChannelUID;
51 import org.openhab.core.thing.Thing;
52 import org.openhab.core.thing.binding.ThingHandlerService;
53 import org.openhab.core.thing.binding.builder.ChannelBuilder;
54 import org.openhab.core.thing.type.ChannelTypeUID;
55 import org.openhab.core.types.Command;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 /**
60  * The {@link ServerHandler} handle common parts of Freebox bridges.
61  *
62  * @author Gaël L'hopital - Initial contribution
63  */
64 @NonNullByDefault
65 public class ServerHandler extends ApiConsumerHandler implements FreeDeviceIntf {
66     private static final BigDecimal HUNDRED = BigDecimal.valueOf(100);
67
68     private final Logger logger = LoggerFactory.getLogger(ServerHandler.class);
69     private final ChannelUID eventChannelUID;
70
71     private long uptime = -1;
72
73     private boolean tryConfigureMediaSink = true;
74
75     public ServerHandler(Thing thing) {
76         super(thing);
77         eventChannelUID = new ChannelUID(getThing().getUID(), GROUP_SYS_INFO, BOX_EVENT);
78     }
79
80     @Override
81     void initializeProperties(Map<String, String> properties) throws FreeboxException {
82         LanConfig lanConfig = getManager(LanManager.class).getConfig();
83         Config config = getManager(SystemManager.class).getConfig();
84
85         properties.put(Thing.PROPERTY_SERIAL_NUMBER, config.serial());
86         properties.put(Thing.PROPERTY_FIRMWARE_VERSION, config.firmwareVersion());
87         properties.put(Thing.PROPERTY_HARDWARE_VERSION, config.modelInfo().prettyName());
88         properties.put(Thing.PROPERTY_MAC_ADDRESS, config.mac().toColonDelimitedString());
89         properties.put(Source.UPNP.name(), lanConfig.name());
90
91         List<Channel> channels = new ArrayList<>(getThing().getChannels());
92
93         // Remove channels of the not active media type
94         Status connectionConfig = getManager(ConnectionManager.class).getConfig();
95         channels.removeIf(c -> (GROUP_FTTH.equals(c.getUID().getGroupId()) && connectionConfig.media() != Media.FTTH)
96                 || (GROUP_XDSL.equals(c.getUID().getGroupId()) && connectionConfig.media() != Media.XDSL));
97
98         // Add temperature sensors
99         config.sensors().forEach(sensor -> {
100             ChannelUID sensorId = new ChannelUID(thing.getUID(), GROUP_SENSORS, sensor.id());
101             if (getThing().getChannel(sensorId) == null) {
102                 String label = sensor.name();
103                 // For revolution, API returns only "Disque dur" so we patch it to have naming consistency with other
104                 // temperature sensors
105                 if ("Disque dur".equals(label)) {
106                     label = "Température " + label;
107                 }
108                 channels.add(ChannelBuilder.create(sensorId).withLabel(label).withAcceptedItemType("Number:Temperature")
109                         .withType(new ChannelTypeUID(BINDING_ID, "temperature")).build());
110             }
111         });
112
113         // Add fans sensors
114         config.fans().forEach(sensor -> {
115             ChannelUID sensorId = new ChannelUID(thing.getUID(), GROUP_FANS, sensor.id());
116             if (getThing().getChannel(sensorId) == null) {
117                 channels.add(ChannelBuilder.create(sensorId).withLabel(sensor.name())
118                         .withAcceptedItemType("Number:Frequency").withType(new ChannelTypeUID(BINDING_ID, "fanspeed"))
119                         .build());
120             }
121         });
122
123         // And finally update the thing with appropriate channels
124         updateThing(editThing().withChannels(channels).build());
125     }
126
127     @Override
128     protected void internalPoll() throws FreeboxException {
129         logger.debug("Polling server state...");
130         fetchConnectionStatus();
131         fetchSystemConfig();
132
133         if (anyChannelLinked(GROUP_ACTIONS, Set.of(WIFI_STATUS))) {
134             updateChannelOnOff(GROUP_ACTIONS, WIFI_STATUS, getManager(WifiManager.class).getStatus());
135         }
136         if (anyChannelLinked(GROUP_ACTIONS, Set.of(AIRMEDIA_STATUS))) {
137             updateChannelOnOff(GROUP_ACTIONS, AIRMEDIA_STATUS, getManager(AirMediaManager.class).getStatus());
138         }
139         if (anyChannelLinked(GROUP_ACTIONS, Set.of(UPNPAV_STATUS))) {
140             updateChannelOnOff(GROUP_ACTIONS, UPNPAV_STATUS, getManager(UPnPAVManager.class).getStatus());
141         }
142
143         if (anyChannelLinked(GROUP_FILE_SHARING, Set.of(SAMBA_FILE_STATUS, SAMBA_PRINTER_STATUS))) {
144             Samba response = getManager(SambaManager.class).getConfig();
145             updateChannelOnOff(GROUP_FILE_SHARING, SAMBA_FILE_STATUS, response.fileShareEnabled());
146             updateChannelOnOff(GROUP_FILE_SHARING, SAMBA_PRINTER_STATUS, response.printShareEnabled());
147         }
148         if (anyChannelLinked(GROUP_FILE_SHARING, Set.of(FTP_STATUS))) {
149             updateChannelOnOff(GROUP_FILE_SHARING, FTP_STATUS, getManager(FtpManager.class).getStatus());
150         }
151         if (anyChannelLinked(GROUP_FILE_SHARING, Set.of(AFP_FILE_STATUS))) {
152             updateChannelOnOff(GROUP_FILE_SHARING, AFP_FILE_STATUS, getManager(AfpManager.class).getStatus());
153         }
154
155         if (tryConfigureMediaSink) {
156             configureMediaSink();
157             tryConfigureMediaSink = false;
158         }
159     }
160
161     @Override
162     protected void internalForcePoll() throws FreeboxException {
163         tryConfigureMediaSink = true;
164         internalPoll();
165     }
166
167     private void fetchSystemConfig() throws FreeboxException {
168         Config config = getManager(SystemManager.class).getConfig();
169
170         config.sensors().forEach(s -> updateChannelQuantity(GROUP_SENSORS, s.id(), s.value(), SIUnits.CELSIUS));
171         config.fans().forEach(f -> updateChannelQuantity(GROUP_FANS, f.id(), f.value(), Units.RPM));
172
173         uptime = checkUptimeAndFirmware(config.uptimeVal(), uptime, config.firmwareVersion());
174         updateChannelQuantity(GROUP_SYS_INFO, UPTIME, uptime, Units.SECOND);
175
176         if (anyChannelLinked(GROUP_SYS_INFO, Set.of(IP_ADDRESS))) {
177             LanConfig lanConfig = getManager(LanManager.class).getConfig();
178             updateChannelString(GROUP_SYS_INFO, IP_ADDRESS, lanConfig.ip());
179         }
180     }
181
182     private void fetchConnectionStatus() throws FreeboxException {
183         if (anyChannelLinked(GROUP_CONNECTION_STATUS,
184                 Set.of(LINE_STATUS, LINE_TYPE, LINE_MEDIA, IP_ADDRESS, IPV6_ADDRESS, BYTES_UP, BYTES_DOWN, RATE + "-up",
185                         BW + "-up", PCT_BW + "-up", RATE + "-down", BW + "-down", PCT_BW + "-down"))) {
186             Status status = getManager(ConnectionManager.class).getConfig();
187             updateChannelString(GROUP_CONNECTION_STATUS, LINE_STATUS, status.state());
188             updateChannelString(GROUP_CONNECTION_STATUS, LINE_TYPE, status.type());
189             updateChannelString(GROUP_CONNECTION_STATUS, LINE_MEDIA, status.media());
190             updateChannelString(GROUP_CONNECTION_STATUS, IP_ADDRESS, status.ipv4());
191             updateChannelString(GROUP_CONNECTION_STATUS, IPV6_ADDRESS, status.ipv6());
192             updateRateBandwidth(status.rateUp(), status.bandwidthUp(), "up");
193             updateRateBandwidth(status.rateDown(), status.bandwidthDown(), "down");
194
195             updateChannelQuantity(GROUP_CONNECTION_STATUS, BYTES_UP, new QuantityType<>(status.bytesUp(), OCTET),
196                     GIBIOCTET);
197             updateChannelQuantity(GROUP_CONNECTION_STATUS, BYTES_DOWN, new QuantityType<>(status.bytesDown(), OCTET),
198                     GIBIOCTET);
199         }
200         if (anyChannelLinked(GROUP_FTTH,
201                 Set.of(SFP_PRESENT, SFP_ALIM, SFP_POWER, SFP_SIGNAL, SFP_LINK, SFP_PWR_TX, SFP_PWR_RX))) {
202             FtthStatus ftthStatus = getManager(ConnectionManager.class).getFtthStatus();
203             updateChannelOnOff(GROUP_FTTH, SFP_PRESENT, ftthStatus.sfpPresent());
204             updateChannelOnOff(GROUP_FTTH, SFP_ALIM, ftthStatus.sfpAlimOk());
205             updateChannelOnOff(GROUP_FTTH, SFP_POWER, ftthStatus.sfpHasPowerReport());
206             updateChannelOnOff(GROUP_FTTH, SFP_SIGNAL, ftthStatus.sfpHasSignal());
207             updateChannelOnOff(GROUP_FTTH, SFP_LINK, ftthStatus.link());
208             updateChannelQuantity(GROUP_FTTH, SFP_PWR_TX, ftthStatus.getTransmitDBM(), Units.DECIBEL_MILLIWATTS);
209             updateChannelQuantity(GROUP_FTTH, SFP_PWR_RX, ftthStatus.getReceivedDBM(), Units.DECIBEL_MILLIWATTS);
210         }
211         if (anyChannelLinked(GROUP_XDSL, Set.of(XDSL_READY, XDSL_STATUS, XDSL_MODULATION, XDSL_UPTIME))) {
212             XdslInfos xdslInfos = getManager(ConnectionManager.class).getXdslStatus();
213             updateChannelOnOff(GROUP_XDSL, XDSL_READY, xdslInfos.status().status() == SynchroState.SHOWTIME);
214             updateChannelString(GROUP_XDSL, XDSL_STATUS, xdslInfos.status().status());
215             updateChannelString(GROUP_XDSL, XDSL_MODULATION, xdslInfos.status().modulation());
216             updateChannelQuantity(GROUP_XDSL, XDSL_UPTIME, xdslInfos.status().uptime(), Units.SECOND);
217         }
218     }
219
220     private void updateRateBandwidth(long rate, long bandwidth, String orientation) {
221         QuantityType<?> rateUp = new QuantityType<>(rate * 8, Units.BIT_PER_SECOND);
222         QuantityType<?> bandwidthUp = new QuantityType<>(bandwidth, BIT_PER_SECOND);
223         updateChannelQuantity(GROUP_CONNECTION_STATUS, RATE + "-" + orientation, rateUp, KILOBIT_PER_SECOND);
224         updateChannelQuantity(GROUP_CONNECTION_STATUS, BW + "-" + orientation, bandwidthUp, KILOBIT_PER_SECOND);
225         updateChannelQuantity(GROUP_CONNECTION_STATUS, PCT_BW + "-" + orientation,
226                 !bandwidthUp.equals(QuantityType.ZERO) ? rateUp.multiply(HUNDRED).divide(bandwidthUp)
227                         : QuantityType.ZERO,
228                 Units.PERCENT);
229     }
230
231     @Override
232     protected boolean internalHandleCommand(String channelId, Command command) throws FreeboxException {
233         if (ON_OFF_CLASSES.contains(command.getClass())) {
234             boolean enable = TRUE_COMMANDS.contains(command);
235             switch (channelId) {
236                 case WIFI_STATUS:
237                     updateChannelOnOff(GROUP_ACTIONS, WIFI_STATUS, getManager(WifiManager.class).setStatus(enable));
238                     return true;
239                 case FTP_STATUS:
240                     updateChannelOnOff(GROUP_FILE_SHARING, FTP_STATUS, getManager(FtpManager.class).setStatus(enable));
241                     return true;
242                 case SAMBA_FILE_STATUS:
243                     updateChannelOnOff(GROUP_FILE_SHARING, SAMBA_FILE_STATUS,
244                             getManager(SambaManager.class).setFileShare(enable));
245                     return true;
246                 case SAMBA_PRINTER_STATUS:
247                     updateChannelOnOff(GROUP_FILE_SHARING, SAMBA_PRINTER_STATUS,
248                             getManager(SambaManager.class).setPrintShare(enable));
249                     return true;
250                 case UPNPAV_STATUS:
251                     updateChannelOnOff(GROUP_ACTIONS, UPNPAV_STATUS, getManager(UPnPAVManager.class).setStatus(enable));
252                     return true;
253                 case AFP_FILE_STATUS:
254                     updateChannelOnOff(GROUP_FILE_SHARING, AFP_FILE_STATUS,
255                             getManager(AfpManager.class).setStatus(enable));
256                     return true;
257                 case AIRMEDIA_STATUS:
258                     updateChannelOnOff(GROUP_ACTIONS, AIRMEDIA_STATUS,
259                             getManager(AirMediaManager.class).setStatus(enable));
260                     tryConfigureMediaSink = true;
261                     return true;
262                 default:
263                     break;
264             }
265         }
266         return super.internalHandleCommand(channelId, command);
267     }
268
269     public void reboot() {
270         processReboot(() -> {
271             try {
272                 getManager(SystemManager.class).reboot();
273             } catch (FreeboxException e) {
274                 logger.warn("Error rebooting: {}", e.getMessage());
275             }
276         });
277     }
278
279     @Override
280     public Collection<Class<? extends ThingHandlerService>> getServices() {
281         return Set.of(ServerActions.class);
282     }
283
284     @Override
285     public ChannelUID getEventChannelUID() {
286         return eventChannelUID;
287     }
288
289     @Override
290     public void triggerChannel(ChannelUID channelUID, String event) {
291         super.triggerChannel(channelUID, event);
292     }
293 }