ESPHome  2024.11.0
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
6 namespace esphome {
7 namespace statsd {
8 
9 // send UDP packet if we reach 1Kb packed size
10 // this is needed since statsD does not support fragmented UDP packets
11 static const uint16_t SEND_THRESHOLD = 1024;
12 
13 static 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, "statsD:");
42  ESP_LOGCONFIG(TAG, " host: %s", this->host_);
43  ESP_LOGCONFIG(TAG, " port: %d", this->port_);
44  if (this->prefix_) {
45  ESP_LOGCONFIG(TAG, " prefix: %s", this->prefix_);
46  }
47 
48  ESP_LOGCONFIG(TAG, " metrics:");
49  for (sensors_t s : this->sensors_) {
50  ESP_LOGCONFIG(TAG, " - name: %s", s.name);
51  ESP_LOGCONFIG(TAG, " type: %d", s.type);
52  }
53 }
54 
56 
57 #ifdef USE_SENSOR
59  sensors_t s;
60  s.name = name;
61  s.sensor = sensor;
62  s.type = TYPE_SENSOR;
63  this->sensors_.push_back(s);
64 }
65 #endif
66 
67 #ifdef USE_BINARY_SENSOR
69  sensors_t s;
70  s.name = name;
71  s.binary_sensor = binary_sensor;
72  s.type = TYPE_BINARY_SENSOR;
73  this->sensors_.push_back(s);
74 }
75 #endif
76 
78  std::string out;
79  out.reserve(SEND_THRESHOLD);
80 
81  for (sensors_t s : this->sensors_) {
82  double val = 0;
83  switch (s.type) {
84 #ifdef USE_SENSOR
85  case TYPE_SENSOR:
86  if (!s.sensor->has_state()) {
87  continue;
88  }
89  val = s.sensor->state;
90  break;
91 #endif
92 #ifdef USE_BINARY_SENSOR
93  case TYPE_BINARY_SENSOR:
94  if (!s.binary_sensor->has_state()) {
95  continue;
96  }
97  // map bool to double
98  if (s.binary_sensor->state) {
99  val = 1;
100  }
101  break;
102 #endif
103  default:
104  ESP_LOGE(TAG, "type not known, name: %s type: %d", s.name, s.type);
105  continue;
106  }
107 
108  // statsD gauge:
109  // https://github.com/statsd/statsd/blob/master/docs/metric_types.md
110  // This implies you can't explicitly set a gauge to a negative number without first setting it to zero.
111  if (val < 0) {
112  if (this->prefix_) {
113  out.append(str_sprintf("%s.", this->prefix_));
114  }
115  out.append(str_sprintf("%s:0|g\n", s.name));
116  }
117  if (this->prefix_) {
118  out.append(str_sprintf("%s.", this->prefix_));
119  }
120  out.append(str_sprintf("%s:%f|g\n", s.name, val));
121 
122  if (out.length() > SEND_THRESHOLD) {
123  this->send_(&out);
124  out.clear();
125  }
126  }
127 
128  this->send_(&out);
129 }
130 
131 void StatsdComponent::send_(std::string *out) {
132  if (out->empty()) {
133  return;
134  }
135 #ifdef USE_ESP8266
136  IPAddress ip;
137  ip.fromString(this->host_);
138 
139  this->sock_.beginPacket(ip, this->port_);
140  this->sock_.write((const uint8_t *) out->c_str(), out->length());
141  this->sock_.endPacket();
142 
143 #else
144  if (!this->sock_) {
145  return;
146  }
147 
148  int n_bytes = this->sock_->sendto(out->c_str(), out->length(), 0, reinterpret_cast<sockaddr *>(&this->destination_),
149  sizeof(this->destination_));
150  if (n_bytes != out->length()) {
151  ESP_LOGE(TAG, "Failed to send UDP packed (%d of %d)", n_bytes, out->length());
152  }
153 #endif
154 }
155 
156 } // namespace statsd
157 } // namespace esphome
158 #endif
const char * name
Definition: stm32flash.h:78
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition: component.cpp:26
void dump_config() override
Definition: statsd.cpp:40
sa_family_t sin_family
Definition: headers.h:63
struct { const char *name sensors_t
Definition: statsd.h:34
mopeka_std_values val[4]
void register_binary_sensor(const char *name, esphome::binary_sensor::BinarySensor *binary_sensor)
Definition: statsd.cpp:68
in_port_t sin_port
Definition: headers.h:64
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:315
float get_setup_priority() const override
Definition: statsd.cpp:55
esphome::binary_sensor::BinarySensor * binary_sensor
Definition: statsd.h:41
struct in_addr sin_addr
Definition: headers.h:65
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
Base class for all binary_sensor-type classes.
Definition: binary_sensor.h:37
void register_sensor(const char *name, esphome::sensor::Sensor *sensor)
Definition: statsd.cpp:58
Base-class for all sensors.
Definition: sensor.h:57
esphome::sensor::Sensor * sensor
Definition: statsd.h:38
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.