2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.netatmo.internal.handler.capability;
15 import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
17 import java.time.ZonedDateTime;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.binding.netatmo.internal.api.EnergyApi;
21 import org.openhab.binding.netatmo.internal.api.NetatmoException;
22 import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.FeatureArea;
23 import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.SetpointMode;
24 import org.openhab.binding.netatmo.internal.api.dto.HomeData;
25 import org.openhab.binding.netatmo.internal.api.dto.HomeDataModule;
26 import org.openhab.binding.netatmo.internal.api.dto.HomeDataRoom;
27 import org.openhab.binding.netatmo.internal.api.dto.HomeStatusModule;
28 import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
29 import org.openhab.binding.netatmo.internal.api.dto.Room;
30 import org.openhab.binding.netatmo.internal.config.HomeConfiguration;
31 import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap;
32 import org.openhab.binding.netatmo.internal.handler.CommonInterface;
33 import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.StateOption;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link EnergyCapability} is the base class for handler able to handle energy features
43 * @author Gaƫl L'hopital - Initial contribution
47 public class EnergyCapability extends RestCapability<EnergyApi> {
48 private final Logger logger = LoggerFactory.getLogger(EnergyCapability.class);
49 private final NetatmoDescriptionProvider descriptionProvider;
51 private int setPointDefaultDuration = -1;
52 private String energyId = "";
54 EnergyCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider) {
55 super(handler, EnergyApi.class);
56 this.descriptionProvider = descriptionProvider;
60 public void initialize() {
62 energyId = handler.getThingConfigAs(HomeConfiguration.class).getIdForArea(FeatureArea.ENERGY);
66 protected void updateHomeData(HomeData homeData) {
67 if (homeData instanceof HomeData.Energy energyData) {
68 NAObjectMap<HomeDataRoom> rooms = energyData.getRooms();
69 NAObjectMap<HomeDataModule> modules = energyData.getModules();
70 handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
71 String childId = childHandler.getId();
73 .ifPresentOrElse(roomData -> childHandler.setNewData(roomData.ignoringForThingUpdate()), () -> {
74 modules.getOpt(childId).ifPresent(
75 childData -> childHandler.setNewData(childData.ignoringForThingUpdate()));
76 modules.values().stream().filter(module -> childId.equals(module.getBridge()))
77 .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
80 descriptionProvider.setStateOptions(new ChannelUID(thingUID, GROUP_ENERGY, CHANNEL_PLANNING),
81 energyData.getThermSchedules().stream().map(p -> new StateOption(p.getId(), p.getName())).toList());
82 setPointDefaultDuration = energyData.getThermSetpointDefaultDuration();
87 protected void updateHomeStatus(HomeStatus energyStatus) {
88 NAObjectMap<Room> rooms = energyStatus.getRooms();
89 NAObjectMap<HomeStatusModule> modules = energyStatus.getModules();
90 handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
91 String childId = childHandler.getId();
92 logger.trace("childId: {}", childId);
93 rooms.getOpt(childId).ifPresentOrElse(roomData -> {
94 logger.trace("roomData: {}", roomData);
95 childHandler.setNewData(roomData);
97 modules.getOpt(childId).ifPresent(moduleData -> {
98 logger.trace("moduleData: {}", moduleData);
99 childHandler.setNewData(moduleData);
100 modules.values().stream().filter(module -> childId.equals(module.getBridge()))
101 .forEach(bridgedModule -> {
102 logger.trace("bridgedModule: {}", bridgedModule);
103 childHandler.setNewData(bridgedModule);
110 public void setThermPoint(String roomId, SetpointMode mode, long endtime, double temp) {
111 getApi().ifPresent(api -> {
113 api.setThermpoint(energyId, roomId, mode, endtime, temp);
114 handler.expireData();
115 } catch (NetatmoException e) {
116 logger.warn("Error setting room thermostat mode '{}' : {}", mode, e.getMessage());
121 public void setRoomThermTemp(String roomId, SetpointMode mode, long endtime, double temp) {
122 setThermPoint(roomId, mode, endtime, temp);
125 public void setRoomThermMode(String roomId, SetpointMode targetMode) {
126 setThermPoint(roomId, targetMode, targetMode == SetpointMode.MAX ? setpointEndTimeFromNow() : 0, 0);
129 public void setRoomThermTemp(String roomId, double temp) {
130 setThermPoint(roomId, SetpointMode.MANUAL, setpointEndTimeFromNow(), temp);
134 public void handleCommand(String channelName, Command command) {
135 getApi().ifPresent(api -> {
137 switch (channelName) {
138 case CHANNEL_PLANNING:
139 api.switchSchedule(energyId, command.toString());
141 case CHANNEL_SETPOINT_MODE:
142 SetpointMode targetMode = SetpointMode.valueOf(command.toString());
143 if (targetMode == SetpointMode.MANUAL) {
144 logger.info("Switch to 'Manual' is done by setting a setpoint temp, command ignored");
147 api.setThermMode(energyId, targetMode.apiDescriptor);
150 handler.expireData();
151 } catch (NetatmoException e) {
152 logger.warn("Error handling command '{}' : {}", command, e.getMessage());
153 } catch (IllegalArgumentException e) {
154 logger.warn("Command '{}' sent to channel '{}' is not a valid setpoint mode.", command, channelName);
159 private long setpointEndTimeFromNow() {
160 return ZonedDateTime.now().plusMinutes(setPointDefaultDuration).toEpochSecond();