ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
statsd.cpp
Go to the documentation of this file.
1#include "esphome/core/log.h"
2
3#include "statsd.h"
4
5#ifdef USE_NETWORK
6namespace esphome {
7namespace statsd {
8
9// send UDP packet if we reach 1Kb packed size
10// this is needed since statsD does not support fragmented UDP packets
11static const uint16_t SEND_THRESHOLD = 1024;
12
13static const char *const TAG = "statsD";
14
16#ifndef USE_ESP8266
17 this->sock_ = esphome::socket::socket(AF_INET, SOCK_DGRAM, 0);
18
19 struct sockaddr_in source;
20 source.sin_family = AF_INET;
21 source.sin_addr.s_addr = htonl(INADDR_ANY);
22 source.sin_port = htons(this->port_);
23 this->sock_->bind((struct sockaddr *) &source, sizeof(source));
24
25 this->destination_.sin_family = AF_INET;
26 this->destination_.sin_port = htons(this->port_);
27 this->destination_.sin_addr.s_addr = inet_addr(this->host_);
28#endif
29}
30
32#ifndef USE_ESP8266
33 if (!this->sock_) {
34 return;
35 }
36 this->sock_->close();
37#endif
38}
39
41 ESP_LOGCONFIG(TAG,
42 "statsD:\n"
43 " host: %s\n"
44 " port: %d",
45 this->host_, this->port_);
46 if (this->prefix_) {
47 ESP_LOGCONFIG(TAG, " prefix: %s", this->prefix_);
48 }
49
50 ESP_LOGCONFIG(TAG, " metrics:");
51 for (sensors_t s : this->sensors_) {
52 ESP_LOGCONFIG(TAG,
53 " - name: %s\n"
54 " type: %d",
55 s.name, s.type);
56 }
57}
58
60
61#ifdef USE_SENSOR
63 sensors_t s;
64 s.name = name;
65 s.sensor = sensor;
66 s.type = TYPE_SENSOR;
67 this->sensors_.push_back(s);
68}
69#endif
70
71#ifdef USE_BINARY_SENSOR
73 sensors_t s;
74 s.name = name;
75 s.binary_sensor = binary_sensor;
76 s.type = TYPE_BINARY_SENSOR;
77 this->sensors_.push_back(s);
78}
79#endif
80
82 std::string out;
83 out.reserve(SEND_THRESHOLD);
84
85 for (sensors_t s : this->sensors_) {
86 double val = 0;
87 switch (s.type) {
88#ifdef USE_SENSOR
89 case TYPE_SENSOR:
90 if (!s.sensor->has_state()) {
91 continue;
92 }
93 val = s.sensor->state;
94 break;
95#endif
96#ifdef USE_BINARY_SENSOR
97 case TYPE_BINARY_SENSOR:
98 if (!s.binary_sensor->has_state()) {
99 continue;
100 }
101 // map bool to double
102 if (s.binary_sensor->state) {
103 val = 1;
104 }
105 break;
106#endif
107 default:
108 ESP_LOGE(TAG, "type not known, name: %s type: %d", s.name, s.type);
109 continue;
110 }
111
112 // statsD gauge:
113 // https://github.com/statsd/statsd/blob/master/docs/metric_types.md
114 // This implies you can't explicitly set a gauge to a negative number without first setting it to zero.
115 if (val < 0) {
116 if (this->prefix_) {
117 out.append(this->prefix_);
118 out.append(".");
119 }
120 out.append(s.name);
121 out.append(":0|g\n");
122 }
123 if (this->prefix_) {
124 out.append(this->prefix_);
125 out.append(".");
126 }
127 out.append(s.name);
128 // Buffer for ":" + value + "|g\n".
129 // %f with -DBL_MAX can produce up to 321 chars, plus ":" and "|g\n" (4) + null = 326
130 char val_buf[330];
131 buf_append_printf(val_buf, sizeof(val_buf), 0, ":%f|g\n", val);
132 out.append(val_buf);
133
134 if (out.length() > SEND_THRESHOLD) {
135 this->send_(&out);
136 out.clear();
137 }
138 }
139
140 this->send_(&out);
141}
142
143void StatsdComponent::send_(std::string *out) {
144 if (out->empty()) {
145 return;
146 }
147#ifdef USE_ESP8266
148 IPAddress ip;
149 ip.fromString(this->host_);
150
151 this->sock_.beginPacket(ip, this->port_);
152 this->sock_.write((const uint8_t *) out->c_str(), out->length());
153 this->sock_.endPacket();
154
155#else
156 if (!this->sock_) {
157 return;
158 }
159
160 int n_bytes = this->sock_->sendto(out->c_str(), out->length(), 0, reinterpret_cast<sockaddr *>(&this->destination_),
161 sizeof(this->destination_));
162 if (n_bytes != static_cast<int>(out->length())) {
163 ESP_LOGE(TAG, "Failed to send UDP packed (%d of %d)", n_bytes, out->length());
164 }
165#endif
166}
167
168} // namespace statsd
169} // namespace esphome
170#endif
Base class for all binary_sensor-type classes.
Base-class for all sensors.
Definition sensor.h:47
void register_sensor(const char *name, esphome::sensor::Sensor *sensor)
Definition statsd.cpp:62
void register_binary_sensor(const char *name, esphome::binary_sensor::BinarySensor *binary_sensor)
Definition statsd.cpp:72
float get_setup_priority() const override
Definition statsd.cpp:59
mopeka_std_values val[4]
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.h:41
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
struct in_addr sin_addr
Definition headers.h:65
sa_family_t sin_family
Definition headers.h:63
in_port_t sin_port
Definition headers.h:64