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