supla-device
Loading...
Searching...
No Matches
mqtt.h
1// SPDX-FileCopyrightText: AC SOFTWARE SP. Z O.O.
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#ifndef SRC_SUPLA_PROTOCOL_MQTT_H_
5#define SRC_SUPLA_PROTOCOL_MQTT_H_
6
7#include <supla/storage/config.h>
8#include <supla/storage/storage.h>
9#include <supla-common/proto.h>
10#include <supla/uptime.h>
11#include <supla/protocol/mqtt_topic.h>
12#include <supla/protocol/mqtt_channel_handler.h>
13#include <supla/element.h>
14
15#include "protocol_layer.h"
16
17// max client id length limit in mqtt 3.1
18#define MQTT_CLIENTID_MAX_SIZE 23
19#define MQTT_MAX_PAYLOAD_LEN 50
20
21namespace Supla {
22
23namespace Protocol {
24
25// https://developers.home-assistant.io/docs/core/entity/sensor/
26enum HAStateClass {
27 HAStateClass_None,
28 HAStateClass_Measurement,
29 HAStateClass_Total,
30 HAStateClass_TotalIncreasing
31};
32
33// https://www.home-assistant.io/integrations/sensor/#device-class
34// Not all devices classes are implemented here. Only those which we use are
35// present. Add more if needed.
36// Also not all parameters used in Supla have corresponding device class in
37// HA, so in such case we don't set the device class.
38enum HADeviceClass {
39 HADeviceClass_None,
40 HADeviceClass_ApparentPower,
41 HADeviceClass_Current,
42 HADeviceClass_Energy,
43 HADeviceClass_ReactiveEnergy,
44 HADeviceClass_Frequency,
45 HADeviceClass_PowerFactor,
46 HADeviceClass_Power,
47 HADeviceClass_ReactivePower,
48 HADeviceClass_Voltage,
49 HADeviceClass_Outlet,
50 HADeviceClass_Gate,
51 HADeviceClass_Door,
52 HADeviceClass_Garage,
53 HADeviceClass_Moisture,
54 HADeviceClass_Window,
55 HADeviceClass_Awning,
56 HADeviceClass_Blind,
57 HADeviceClass_Curtain,
58 HADeviceClass_Shutter,
59 HADeviceClass_Shade,
60 HADeviceClass_GarageDoor,
61};
62
63class HvacMqttHandler;
64
65class Mqtt : public ProtocolLayer {
66 public:
67 explicit Mqtt(SuplaDeviceClass *sdc);
68 virtual ~Mqtt();
69
70 void onInit() override;
71 bool onLoadConfig() override;
72 bool verifyConfig() override;
73 bool isEnabled() override;
74// void disconnect() override;
75// void iterate(uint32_t _millis) override;
76 bool isNetworkRestartRequested() override;
77 uint32_t getConnectionFailTime() override;
78 bool isConnectionError() override;
79 bool isConnecting() override;
80 bool isMqtt() const override;
81 void publish(const char *topic,
82 const char *payload,
83 int qos = -1,
84 int retain = -1,
85 bool ignorePrefix = false);
86 void publishInt(const char *topic,
87 int payload,
88 int qos = -1,
89 int retain = -1);
90 void publishBool(const char *topic,
91 bool payload,
92 int qos = -1,
93 int retain = -1);
94 void publishOnOff(const char *topic, bool payload, int qos, int retain);
95 void publishOpenClosed(const char *topic, bool payload, int qos, int retain);
96 void publishDouble(const char *topic,
97 double payload,
98 int qos = -1,
99 int retain = -1,
100 int precision = 2);
101 void publishColor(const char *topic,
102 uint8_t red,
103 uint8_t green,
104 uint8_t blue,
105 int qos = -1,
106 int retain = -1);
107 void publishChannelState(int channel);
108 void publishExtendedChannelState(int channel);
109 void subscribeChannel(int channel);
110 void unsubscribeChannel(int channel);
111 const char *getPrefix() const;
112 const char *getHostname() const;
113 void subscribe(const char *topic, int qos = -1);
114 void unsubscribe(const char *topic);
115 bool isUpdatePending() override;
116 bool isRegisteredAndReady() override;
117 void notifyConfigChange(int channelNumber) override;
118
119 void sendActionTrigger(uint8_t channelNumber, uint32_t actionId) override;
120 void sendChannelValueChanged(uint8_t channelNumber, int8_t *value,
121 unsigned char offline, uint32_t validityTimeSec) override;
122 void sendExtendedChannelValueChanged(uint8_t channelNumber,
123 TSuplaChannelExtendedValue *value) override;
124
125 bool processData(const char *topic, const char *payload);
126 void processRelayRequest(const char *topic,
127 const char *payload,
128 Supla::Element *element,
129 Supla::Channel *channel);
130 void processRGBWRequest(const char *topic,
131 const char *payload,
132 Supla::Element *element,
133 int channelNumber);
134 void processRGBRequest(const char *topic,
135 const char *payload,
136 Supla::Element *element,
137 int channelNumber);
138 void processDimmerRequest(const char *topic,
139 const char *payload,
140 Supla::Element *element,
141 int channelNumber);
142 void processRollerShutterRequest(const char *topic,
143 const char *payload,
144 Supla::Element *element,
145 int channelNumber);
146
147 protected:
148 void generateClientId(char result[MQTT_CLIENTID_MAX_SIZE]);
149 void generateObjectId(char result[30], int channelNumber, int subId);
150 MqttTopic getHADiscoveryTopic(const char *sensor, char *objectId);
151 void publishDeviceStatus(bool onRegistration = false);
152 void publishChannelSetup(int channelNumber);
153 bool isChannelAvailableForHa(const Supla::Channel *channel) const;
154 void publishChannelAvailability(int channelNumber, bool force = false);
155 void resetChannelAvailabilityCache();
156 const char *getHAAvailability(const Supla::Channel *channel);
157 void getHAExpireAfter(const Supla::Channel *channel,
158 char *result,
159 size_t resultSize) const;
160 void processConfigChanges();
161 void publishHADiscovery(int channel);
162 void publishHADiscoveryRelay(Supla::Element *);
163 void publishHADiscoveryRelay(Supla::Element *, Supla::Channel *);
164 void publishHADiscoveryRelayImpulse(Supla::Element *);
165 void publishHADiscoveryRelayImpulse(Supla::Element *, Supla::Channel *);
166 void clearHADiscoveryRelayAlternativeTypes(Supla::Channel *channel,
167 const char *currentType);
168 void clearHADiscoveryForChannel(Supla::Channel *channel);
169 void clearRelayAlternativeStateTopics(Supla::Channel *channel,
170 bool currentIsRoller);
171 void clearStateForChannel(Supla::Channel *channel);
172 void publishHADiscoveryThermometer(Supla::Element *);
173 void publishHADiscoveryHumidity(Supla::Element *);
174 void publishHADiscoveryActionTrigger(Supla::Element *);
175 void publishHADiscoveryEM(Supla::Element *);
176 void publishHADiscoveryRGB(Supla::Element *);
177 void publishHADiscoveryDimmer(Supla::Element *);
178 void publishHADiscoveryBinarySensor(Supla::Element *);
179 void publishHADiscoveryRollerShutter(Supla::Element *);
180
181 // parameterName has to be ASCII string with small caps and underscores
182 // between words i.e. "total_forward_active_energy".
183 // Name of parameter will be generated in following way:
184 // "Total forward active energy"
185 void publishHADiscoveryEMParameter(
186 Supla::Element *element, int parameterId, const char *parameterName,
187 const char *units, Supla::Protocol::HAStateClass stateClass,
188 Supla::Protocol::HADeviceClass deviceClass);
189 const char *getActionTriggerType(uint8_t actionIdx);
190 bool isActionTriggerEnabled(Supla::Channel *ch, uint8_t actionIdx);
191 virtual void publishImp(const char *topic,
192 const char *payload,
193 int qos,
194 bool retain) = 0;
195 virtual void subscribeImp(const char *topic, int qos) = 0;
196 virtual void unsubscribeImp(const char *topic) = 0;
197 const char *getStateClassStr(Supla::Protocol::HAStateClass stateClass);
198 const char *getDeviceClassStr(Supla::Protocol::HADeviceClass deviceClass);
199
200 const char *getRelayChannelName(int channelFunction) const;
201 const char *getBinarySensorChannelName(int channelFunction) const;
202
203 bool isPayloadOn(const char *);
204 bool isOpenClosedBinarySensorFunction(int channelFunction) const;
205
206 MqttChannelHandler *findChannelHandler(int channelType) const;
207
208 friend class HvacMqttHandler;
209
210 char server[SUPLA_SERVER_NAME_MAXSIZE] = {};
211 int32_t port = -1;
212 char user[MQTT_USERNAME_MAX_SIZE] = {};
213 char password[MQTT_PASSWORD_MAX_SIZE] = {};
214 char hostname[32] = {};
215 uint8_t qosCfg = 0;
216 bool useTls = false;
217 bool useAuth = true;
218 bool retainCfg = false;
219 bool enabled = true;
220 bool connecting = false;
221 bool connected = false;
222 bool error = false;
223 uint16_t prefixLen = 0;
224 uint16_t channelsCount = 0;
225 uint16_t buttonNumber = 0;
226 char *prefix = nullptr;
227 // Button number is incremented on each publishHADiscoveryActionTrigger call
228 // and it is reset on publishDeviceStatus. So we publish button numbers
229 // starting from 1 and incrementing on each ActionTrigger channel found
230 // in current setup.
231 // It is important to call publishDeviceStatus first, then to call
232 // publishHADiscoveryActionTrigger for each AT channel.
233 static constexpr size_t CONFIG_CHANGED_BIT_SIZE =
234 (SUPLA_CHANNELMAXCOUNT + 7) / 8;
235 static_assert(CONFIG_CHANGED_BIT_SIZE * 8 >= SUPLA_CHANNELMAXCOUNT,
236 "MQTT config change bitset is too small");
237 uint8_t configChangedBit[CONFIG_CHANGED_BIT_SIZE] = {};
238 static constexpr size_t CHANNEL_AVAILABILITY_BIT_SIZE =
239 (SUPLA_CHANNELMAXCOUNT + 7) / 8;
240 static_assert(CHANNEL_AVAILABILITY_BIT_SIZE * 8 >= SUPLA_CHANNELMAXCOUNT,
241 "MQTT channel availability bitset is too small");
242 uint8_t channelAvailabilityKnownBit[CHANNEL_AVAILABILITY_BIT_SIZE] = {};
243 uint8_t channelAvailabilityValueBit[CHANNEL_AVAILABILITY_BIT_SIZE] = {};
244 uint8_t channelOnlineButNotAvailableBit[CHANNEL_AVAILABILITY_BIT_SIZE] = {};
245 static constexpr size_t HA_AVAILABILITY_BUFFER_SIZE = 400;
246 char haAvailability[HA_AVAILABILITY_BUFFER_SIZE] = {};
247 Supla::Uptime uptime;
248};
249} // namespace Protocol
250} // namespace Supla
251
252#endif // SRC_SUPLA_PROTOCOL_MQTT_H_
Definition SuplaDevice.h:167
Definition channel.h:26
Base class for all elements of SuplaDevice.
Definition element.h:27
Definition hvac_mqtt.cpp:25
Definition mqtt_channel_handler.h:15
Definition mqtt_topic.h:12
Definition mqtt.h:65
Definition protocol_layer.h:18
Definition uptime.h:11
Definition proto.h:784