denko 0.13.3 → 0.13.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,308 @@
1
+ module Denko
2
+ module Sensor
3
+ class QMP6988
4
+ include I2C::Peripheral
5
+ include Behaviors::Poller
6
+
7
+ UPDATE_TIME = 0.020
8
+ RESET_REGISTER = 0xE0
9
+ RESET_COMMAND = 0xE6
10
+ CTRL_MEAS_REGISTER = 0xF4
11
+ STANDBY_TIME_REGISTER = 0xF5
12
+ IIR_REGISTER = 0xF1
13
+ CONFIG_LENGTH = 5
14
+ DATA_REGISTER = 0xF7
15
+ DATA_LENGTH = 6
16
+ CALIBRATION_REGISTER = 0xA0
17
+ CALIBRATION_LENGTH = 25
18
+ CHIP_ID_REGISTER = 0xD1
19
+ CHIP_ID_LENGTH = 1
20
+ FORCED_MODE = 0b01
21
+ NORMAL_MODE = 0b11
22
+
23
+ # Standby Times for Normal (Continuous) Mode in milliseconds
24
+ STANDBY_TIMES = {
25
+ 1 => 0b000,
26
+ 5 => 0b001,
27
+ 50 => 0b010,
28
+ 250 => 0b011,
29
+ 500 => 0b100,
30
+ 1000 => 0b101,
31
+ 2000 => 0b110,
32
+ 4000 => 0b111,
33
+ }
34
+
35
+ #
36
+ # Oversample Setting Values
37
+ # Note: Each sensor has a separate oversample setting.
38
+ #
39
+ # General formula:
40
+ # 2 ** (n-1), where n is the decimal value of the bits, up to 16x max oversampling.
41
+ #
42
+ OVERSAMPLE_FACTORS = {
43
+ # 0 => 0b000, # Sensor skipped. Value will be 0x800000.
44
+ 1 => 0b001,
45
+ 2 => 0b010,
46
+ 4 => 0b011,
47
+ 8 => 0b100,
48
+ 16 => 0b101,
49
+ 32 => 0b110,
50
+ 64 => 0b111,
51
+ }
52
+ #
53
+ # Single sample times (in milliseconds) for each sensor, derived from datasheet examples.
54
+ TEMPERATURE_SAMPLE_TIME = 0.9
55
+ PRESSURE_SAMPLE_TIME = 0.85
56
+
57
+ # IIR Filter Coefficients
58
+ IIR_COEFFICIENTS = {
59
+ 0 => 0b000,
60
+ 2 => 0b001,
61
+ 4 => 0b010,
62
+ 8 => 0b011,
63
+ 16 => 0b100,
64
+ 32 => 0b101, # 0b110 and 0b111 are also valid for 16.
65
+ }
66
+
67
+ def before_initialize(options={})
68
+ @i2c_address = 0x70
69
+ super(options)
70
+ end
71
+
72
+ def after_initialize(options={})
73
+ super(options)
74
+
75
+ # Avoid repeated memory allocation for callback data and state.
76
+ @reading = { temperature: nil, pressure: nil }
77
+ self.state = { temperature: nil, pressure: nil }
78
+
79
+ reset
80
+
81
+ # Get 5 config registers. Copy 0xF4 to modify it for control.
82
+ get_config_registers
83
+ @ctrl_meas_register = @registers[:f4].dup
84
+
85
+ # Default settings
86
+ self.iir_coefficient = 0
87
+ self.temperature_samples = 1
88
+ self.pressure_samples = 1
89
+ self.forced_mode
90
+
91
+ # self.forced mode triggered an initial measurement so IIR works properly if enabled.
92
+ # Wait for those values to enter the data registers, but don't read them back.
93
+ sleep @measurement_time
94
+
95
+ get_calibration_data
96
+ end
97
+
98
+ #
99
+ # Configuration Methods
100
+ #
101
+ def reset
102
+ i2c_write [RESET_REGISTER, RESET_COMMAND]
103
+ sleep UPDATE_TIME
104
+ end
105
+
106
+ def iir_coefficient=(coeff)
107
+ raise ArgumentError, "invalid IIR coefficient: #{coeff}" unless IIR_COEFFICIENTS.keys.include? coeff
108
+ i2c_write [IIR_REGISTER, IIR_COEFFICIENTS[coeff]]
109
+ @iir_coefficient = coeff
110
+ end
111
+ attr_reader :iir_coefficient
112
+
113
+ def standby_time=(ms)
114
+ raise ArgumentError, "invalid standby time: #{ms}" unless self.class::STANDBY_TIMES.keys.include? ms
115
+ byte = STANDBY_TIMES[ms] << 5
116
+ @standby_time = ms
117
+ i2c_write [STANDBY_TIME_REGISTER, byte]
118
+ sleep UPDATE_TIME
119
+ end
120
+ attr_reader :standby_time
121
+
122
+ def temperature_samples=(factor)
123
+ raise ArgumentError, "invalid oversampling factor: #{factor}" unless OVERSAMPLE_FACTORS.keys.include? factor
124
+ @ctrl_meas_register = (@ctrl_meas_register & 0b00011111) | (OVERSAMPLE_FACTORS[factor] << 5)
125
+ @temperature_samples = factor
126
+ calculate_measurement_time
127
+ i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register]
128
+ sleep UPDATE_TIME
129
+ end
130
+ attr_reader :temperature_samples
131
+
132
+ def pressure_samples=(factor)
133
+ raise ArgumentError, "invalid oversampling factor: #{factor}" unless OVERSAMPLE_FACTORS.keys.include? factor
134
+ @ctrl_meas_register = (@ctrl_meas_register & 0b11100011) | (OVERSAMPLE_FACTORS[factor] << 2)
135
+ @pressure_samples = factor
136
+ calculate_measurement_time
137
+ i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register]
138
+ sleep UPDATE_TIME
139
+ end
140
+ attr_reader :pressure_samples
141
+
142
+ def calculate_measurement_time
143
+ @measurement_time = (@temperature_samples.to_i * TEMPERATURE_SAMPLE_TIME) +
144
+ (@pressure_samples.to_i * PRESSURE_SAMPLE_TIME)
145
+ # Add 5ms for safety and convert to seconds.
146
+ @measurement_time = (@measurement_time + 5) * 0.001
147
+ end
148
+
149
+ def forced_mode
150
+ @ctrl_meas_register = (@ctrl_meas_register & 0b11111100) | FORCED_MODE
151
+ i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register]
152
+ @forced_mode = true
153
+ sleep UPDATE_TIME
154
+ end
155
+
156
+ def continuous_mode
157
+ @ctrl_meas_register = (@ctrl_meas_register & 0b11111100) | NORMAL_MODE
158
+ i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register]
159
+ @forced_mode = false
160
+ sleep UPDATE_TIME
161
+ end
162
+
163
+ def chip_id
164
+ return @chip_id if @chip_id
165
+ i2c_read(CHIP_ID_REGISTER, 1)
166
+ sleep 0.001 while !@chip_id
167
+ @chip_id
168
+ end
169
+
170
+ #
171
+ # Reading & Processing
172
+ #
173
+ def _read
174
+ if @forced_mode
175
+ # Write CTRL_MEAS register to trigger reading, then wait for measurement.
176
+ i2c_write [CTRL_MEAS_REGISTER, @ctrl_meas_register]
177
+ sleep @measurement_time
178
+ end
179
+
180
+ # Read the data bytes.
181
+ i2c_read(DATA_REGISTER, DATA_LENGTH)
182
+ end
183
+
184
+ def pre_callback_filter(bytes)
185
+ if bytes.length == DATA_LENGTH
186
+ return process_reading(bytes)
187
+ elsif bytes.length == CONFIG_LENGTH
188
+ process_config(bytes)
189
+ elsif bytes.length == CALIBRATION_LENGTH
190
+ process_calibration(bytes)
191
+ elsif bytes.length == CHIP_ID_LENGTH
192
+ @chip_id = bytes[0]
193
+ end
194
+ return nil
195
+ end
196
+
197
+ def process_reading(bytes)
198
+ # Temperature and pressure are 24-bits long each, and need 2^23 subtracted.
199
+ dt = ((bytes[3] << 16) + (bytes[4] << 8) + bytes[5]) - (0b1 << 23)
200
+ dp = ((bytes[0] << 16) + (bytes[1] << 8) + bytes[2]) - (0b1 << 23)
201
+
202
+ # Compensated temperature calculated in 1/256 of a degree Celsius.
203
+ tr = @calibration[:a0] +
204
+ @calibration[:a1] * dt +
205
+ @calibration[:a2] * (dt ** 2)
206
+ @reading[:temperature] = tr / 256.0
207
+
208
+ # Compensated pressure calculated in Pascals.
209
+ @reading[:pressure] = @calibration[:b00] +
210
+ @calibration[:bt1] * tr +
211
+ @calibration[:bp1] * dp +
212
+ @calibration[:b11] * (tr * dp) +
213
+ @calibration[:bt2] * (tr ** 2) +
214
+ @calibration[:bp2] * (dp ** 2) +
215
+ @calibration[:b12] * (dp * (tr ** 2)) +
216
+ @calibration[:b21] * ((dp ** 2) * tr) +
217
+ @calibration[:bp3] * (dp ** 3)
218
+
219
+ # Return reading for callbacks.
220
+ @reading
221
+ end
222
+
223
+ def update_state(reading)
224
+ @state_mutex.synchronize do
225
+ @state[:temperature] = reading[:temperature]
226
+ @state[:pressure] = reading[:pressure]
227
+ end
228
+ end
229
+
230
+ def get_config_registers
231
+ @registers = {}
232
+ i2c_read(IIR_REGISTER, CONFIG_LENGTH)
233
+ sleep 0.001 while @registers.empty?
234
+ @registers
235
+ end
236
+
237
+ def process_config(bytes)
238
+ @registers = { f1: bytes[0], f2: bytes[1], f3: bytes[2], f4: bytes[3], f5: bytes[4] }
239
+ end
240
+ attr_reader :registers
241
+
242
+ #
243
+ # Calibration
244
+ #
245
+ attr_reader :calibration_data_loaded
246
+
247
+ CONVERSION_FACTORS = {
248
+ a1: { A: -6.3e-03, S: 4.3e-04 },
249
+ a2: { A: -1.9e-11, S: 1.2e-10 },
250
+ bt1: { A: 1.0e-01, S: 9.1e-02 },
251
+ bt2: { A: 1.2e-08, S: 1.2e-06 },
252
+ bp1: { A: 3.3e-02, S: 1.9e-02 },
253
+ b11: { A: 2.1e-07, S: 1.4e-07 },
254
+ bp2: { A: -6.3e-10, S: 3.5e-10 },
255
+ b12: { A: 2.9e-13, S: 7.6e-13 },
256
+ b21: { A: 2.1e-15, S: 1.2e-14 },
257
+ bp3: { A: 1.3e-16, S: 7.9e-17 },
258
+ a0: 16.0,
259
+ b00: 16.0,
260
+ }
261
+
262
+ def get_calibration_data
263
+ i2c_read(CALIBRATION_REGISTER, CALIBRATION_LENGTH)
264
+ end
265
+
266
+ def process_calibration(bytes)
267
+ if bytes
268
+ # These 2 values are 20-bit instead of 16-bit, so can't combine them with #pack.
269
+ a0_unsigned = (bytes[18] << 12) + (bytes[19] << 4) + (bytes[24] & 0b00001111)
270
+ b00_unsigned = (bytes[0] << 12) + (bytes[1] << 4) + ((bytes[24] & 0b11110000) >> 4)
271
+
272
+ # Cast the raw bytes as big-endian signed.
273
+ @calibration_raw = {
274
+ # Shift these to 32-bit before converting to signed, then reverse the shift after.
275
+ a0: [(a0_unsigned << 12)].pack('L>').unpack('l>')[0] >> 12,
276
+ b00: [(b00_unsigned << 12)].pack('L>').unpack('l>')[0] >> 12,
277
+
278
+ a1: bytes[20..21].pack('C*').unpack('s>')[0],
279
+ a2: bytes[22..23].pack('C*').unpack('s>')[0],
280
+
281
+ b11: bytes[8..9].pack('C*').unpack('s>')[0],
282
+ b12: bytes[12..13].pack('C*').unpack('s>')[0],
283
+ b21: bytes[14..15].pack('C*').unpack('s>')[0],
284
+
285
+ bp1: bytes[6..7].pack('C*').unpack('s>')[0],
286
+ bp2: bytes[10..11].pack('C*').unpack('s>')[0],
287
+ bp3: bytes[16..17].pack('C*').unpack('s>')[0],
288
+
289
+ bt1: bytes[2..3].pack('C*').unpack('s>')[0],
290
+ bt2: bytes[4..5].pack('C*').unpack('s>')[0],
291
+ }
292
+
293
+ # Use conversion formulae to calculate compensation coefficients, all as floats.
294
+ @calibration = {}
295
+ @calibration_raw.keys.each do |key|
296
+ if CONVERSION_FACTORS[key].class == Float
297
+ @calibration[key] = @calibration_raw[key] / CONVERSION_FACTORS[key]
298
+ else
299
+ @calibration[key] = CONVERSION_FACTORS[key][:A] + (CONVERSION_FACTORS[key][:S] * @calibration_raw[key] / 32767.0)
300
+ end
301
+ end
302
+
303
+ @calibration_data_loaded = true
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
@@ -0,0 +1,34 @@
1
+ module Denko
2
+ module Sensor
3
+ class RCWL9620
4
+ include I2C::Peripheral
5
+ include Behaviors::Poller
6
+
7
+ def before_initialize(options={})
8
+ @i2c_address = 0x57
9
+ super(options)
10
+ end
11
+
12
+ def _read
13
+ i2c_write(0x01)
14
+ sleep(0.120)
15
+ i2c_read(nil, 3)
16
+ end
17
+
18
+ def pre_callback_filter(bytes)
19
+ # Data is in micrometers, 3 bytes, big-endian.
20
+ um = (bytes[0] << 16) + (bytes[1] << 8) + bytes[2]
21
+ mm = um / 1000.0
22
+
23
+ # Limit output between 20 and 4500mm.
24
+ if mm > 4500.0
25
+ return 4500.0
26
+ elsif mm < 20.0
27
+ return 20.0
28
+ else
29
+ return mm
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,128 @@
1
+ module Denko
2
+ module Sensor
3
+ class SHT3X
4
+ include I2C::Peripheral
5
+ include Behaviors::Poller
6
+
7
+ RESET = 0x30A2
8
+ RESET_TIME = 0.002
9
+ HEATER_OFF = 0x3066
10
+ HEATER_ON = 0x306D
11
+ FETCH_DATA = 0xE000
12
+ REPEATABILITY = {
13
+ high: { lsb: 0x00, measurement_time: 0.016 },
14
+ medium: { lsb: 0x0B, measurement_time: 0.007 },
15
+ low: { lsb: 0x16, measurement_time: 0.005 },
16
+ }
17
+
18
+ # Unused
19
+ READ_STATUS_REGISTER = 0xF32D
20
+ CLEAR_STATUS_REGISTER = 0x3041
21
+ BREAK = 0x3093
22
+ ART = 0x2B32
23
+
24
+ def before_initialize(options={})
25
+ @i2c_address = 0x44
26
+ super(options)
27
+ end
28
+
29
+ def after_initialize(options={})
30
+ super(options)
31
+
32
+ # Avoid repeated memory allocation for callback data and state.
33
+ @reading = { temperature: nil, humidity: nil }
34
+ self.state = { temperature: nil, humidity: nil }
35
+
36
+ reset
37
+ self.repeatability = :high
38
+ end
39
+
40
+ def repeatability=(key)
41
+ raise ArgumentError, "invalid repeatability setting: #{key}" unless REPEATABILITY.keys.include? key
42
+ @measurement_lsb = REPEATABILITY[key][:lsb]
43
+ @measurement_time = REPEATABILITY[key][:measurement_time]
44
+ end
45
+
46
+ def _read
47
+ i2c_write [0x24, @measurement_lsb]
48
+ sleep(@measurement_time)
49
+ i2c_read(FETCH_DATA, 6)
50
+ end
51
+
52
+ def pre_callback_filter(bytes)
53
+ # Temperature is bytes 0 to 2: MSB, LSB, CRC
54
+ if calculate_crc(bytes[0..2]) == bytes[2]
55
+ t_raw = (bytes[0] << 8) | bytes[1]
56
+ @reading[:temperature] = (175 * t_raw / 65535.0) - 45
57
+ else
58
+ @reading[:temperature] = nil
59
+ end
60
+
61
+ # Humidity is bytes 3 to 5: MSB, LSB, CRC
62
+ if calculate_crc(bytes[3..5]) == bytes[5]
63
+ h_raw = (bytes[3] << 8) | bytes[4]
64
+ @reading[:humidity] = 100 * h_raw / 65535.0
65
+ else
66
+ @reading[:humidity] = nil
67
+ end
68
+
69
+ @reading
70
+ end
71
+
72
+ def update_state(reading)
73
+ @state_mutex.synchronize do
74
+ @state[:temperature] = reading[:temperature]
75
+ @state[:humidity] = reading[:humidity]
76
+ end
77
+ end
78
+
79
+ def reset
80
+ i2c_write [RESET]
81
+ sleep RESET_TIME
82
+ @heater_on = false
83
+ end
84
+
85
+ def heater_on?
86
+ @heater_on
87
+ end
88
+
89
+ def heater_off?
90
+ !@heater_on
91
+ end
92
+
93
+ def heater_on
94
+ i2c_write [HEATER_ON]
95
+ @heater_on = true
96
+ end
97
+
98
+ def heater_off
99
+ i2c_write [HEATER_OFF]
100
+ @heater_on = false
101
+ end
102
+
103
+ # CRC is same as AHT20 sensor. Copied from that file.
104
+ CRC_INITIAL_VALUE = 0xFF
105
+ CRC_POLYNOMIAL = 0x31
106
+ MSBIT_MASK = 0x80
107
+
108
+ def calculate_crc(bytes)
109
+ crc = CRC_INITIAL_VALUE
110
+
111
+ # Ignore last byte. That's the CRC value to compare with.
112
+ bytes.take(bytes.length - 1).each do |byte|
113
+ crc = crc ^ byte
114
+ 8.times do
115
+ if (crc & MSBIT_MASK) > 0
116
+ crc = (crc << 1) ^ CRC_POLYNOMIAL
117
+ else
118
+ crc = crc << 1
119
+ end
120
+ end
121
+ end
122
+
123
+ # Limit CRC size to 8 bits.
124
+ crc = crc & 0xFF
125
+ end
126
+ end
127
+ end
128
+ end
data/lib/denko/sensor.rb CHANGED
@@ -4,10 +4,17 @@ module Denko
4
4
  autoload :Humidity, "#{__dir__}/sensor/virtual"
5
5
  autoload :DHT, "#{__dir__}/sensor/dht"
6
6
  autoload :DS18B20, "#{__dir__}/sensor/ds18b20"
7
+ autoload :BMP180, "#{__dir__}/sensor/bmp180"
7
8
  autoload :BME280, "#{__dir__}/sensor/bme280"
9
+ autoload :BMP280, "#{__dir__}/sensor/bme280"
8
10
  autoload :HTU21D, "#{__dir__}/sensor/htu21d"
9
11
  autoload :HTU31D, "#{__dir__}/sensor/htu31d"
10
12
  autoload :AHT10, "#{__dir__}/sensor/aht"
11
13
  autoload :AHT20, "#{__dir__}/sensor/aht"
14
+ autoload :SHT3X, "#{__dir__}/sensor/sht3x"
15
+ autoload :QMP6988, "#{__dir__}/sensor/qmp6988"
16
+ autoload :RCWL9620, "#{__dir__}/sensor/rcwl9620"
17
+ autoload :HCSR04, "#{__dir__}/sensor/hcsr04"
18
+ autoload :GenericPIR, "#{__dir__}/sensor/generic_pir"
12
19
  end
13
20
  end
data/lib/denko/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Denko
2
- VERSION = "0.13.3"
2
+ VERSION = "0.13.5"
3
3
  end
data/src/denko_wifi.ino CHANGED
@@ -30,8 +30,8 @@
30
30
  #elif defined(ESP32)
31
31
  #include <WiFi.h>
32
32
  #include <ESPmDNS.h>
33
- // #include <WiFiUdp.h>
34
- // #include <ArduinoOTA.h>
33
+ #include <WiFiUdp.h>
34
+ #include <ArduinoOTA.h>
35
35
  #define WIFI_STATUS_LED 2
36
36
  #else
37
37
  #define WIFI_STATUS_LED 13
@@ -48,13 +48,13 @@
48
48
  #endif
49
49
 
50
50
  // Configure your WiFi options here. IP address is not configurable. Uses DHCP.
51
- int port = 3466;
52
- char* ssid = "yourNetwork";
53
- char* pass = "yourPassword";
51
+ #define DENKO_TCP_PORT 3466
52
+ #define WIFI_SSID "yourNetwork"
53
+ #define WIFI_PASSWORD "yourPassword"
54
54
  boolean connected = false;
55
55
 
56
56
  Denko denko;
57
- WiFiServer server(port);
57
+ WiFiServer server(DENKO_TCP_PORT);
58
58
  WiFiClient client;
59
59
 
60
60
  // Use the built in LED to indicate WiFi status.
@@ -82,7 +82,7 @@ void printWifiStatus() {
82
82
  DENKO_SERIAL_IF.println(WiFi.localIP());
83
83
  #endif
84
84
  DENKO_SERIAL_IF.print("Denko TCP Port: ");
85
- DENKO_SERIAL_IF.println(port);
85
+ DENKO_SERIAL_IF.println(DENKO_TCP_PORT);
86
86
  indicateWiFi(true);
87
87
  }
88
88
 
@@ -94,7 +94,7 @@ void connect(){
94
94
 
95
95
  // Try to connect.
96
96
  DENKO_SERIAL_IF.print("Connecting to WiFi ");
97
- WiFi.begin(ssid, pass);
97
+ WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
98
98
 
99
99
  // Delay until connected.
100
100
  while (WiFi.status() != WL_CONNECTED) {
@@ -117,14 +117,39 @@ void setup() {
117
117
  DENKO_SERIAL_IF.begin(115200);
118
118
  while(!DENKO_SERIAL_IF);
119
119
 
120
- // Enable over the air updates on the ESP8266.
121
- #if defined(ESP8266)
120
+ // Attempt initial WiFi connection.
121
+ connect();
122
+
123
+ // Enable over the air updates on the ESP8266 and ESP32.
124
+ // Taken from standard ESP8266/ESP32 OTA examples.
125
+ #if defined(ESP8266) || (ESP32)
126
+ ArduinoOTA.onStart([]() {
127
+ String type;
128
+ if (ArduinoOTA.getCommand() == U_FLASH) {
129
+ type = "sketch";
130
+ } else { // U_FS (ESP8266) or U_SPIFFS (ESP32)
131
+ type = "filesystem";
132
+ }
133
+ // NOTE: if updating FS or SPIFFS, this would be the place to unmount using FS.end() or SPIFFS.end()
134
+ Serial.println("Arduino OTA: Start updating " + type);
135
+ });
136
+ ArduinoOTA.onEnd([]() {
137
+ Serial.println("\nArduino OTA: End\n");
138
+ });
139
+ ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
140
+ Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
141
+ });
142
+ ArduinoOTA.onError([](ota_error_t error) {
143
+ Serial.printf("Error[%u]: ", error);
144
+ if (error == OTA_AUTH_ERROR) Serial.println("Arduino OTA: Auth Failed");
145
+ else if (error == OTA_BEGIN_ERROR) Serial.println("Arduino OTA: Begin Failed");
146
+ else if (error == OTA_CONNECT_ERROR) Serial.println("Arduino OTA: Connect Failed");
147
+ else if (error == OTA_RECEIVE_ERROR) Serial.println("Arduino OTA: Receive Failed");
148
+ else if (error == OTA_END_ERROR) Serial.println("Arduino OTA: End Failed");
149
+ });
122
150
  ArduinoOTA.begin();
123
151
  #endif
124
152
 
125
- // Attempt initial WiFi connection.
126
- connect();
127
-
128
153
  // Start the denko TCP server.
129
154
  server.begin();
130
155
 
@@ -141,7 +166,7 @@ void loop() {
141
166
  maintainWiFi();
142
167
 
143
168
  // Handle OTA updates.
144
- #if defined(ESP8266)
169
+ #if defined(ESP8266) || (ESP32)
145
170
  ArduinoOTA.handle();
146
171
  #endif
147
172
 
data/src/lib/Denko.cpp CHANGED
@@ -3,6 +3,9 @@
3
3
  */
4
4
  #include "Denko.h"
5
5
  #include "BoardMap.h"
6
+ #ifdef DENKO_EEPROM
7
+ #include "EEPROM.h"
8
+ #endif
6
9
 
7
10
  Denko::Denko(){
8
11
  messageFragments[0] = cmdStr;
@@ -119,7 +122,8 @@ void Denko::process() {
119
122
  #endif
120
123
 
121
124
  // Implemented in DenkoPulseInput.cpp
122
- case 9: pulseRead (); break;
125
+ case 9: pulseRead (); break;
126
+ case 20: hcsr04Read (); break;
123
127
 
124
128
  // Implemented in DenkoServo.cpp
125
129
  #ifdef DENKO_SERVO
@@ -275,7 +279,7 @@ void Denko::handshake() {
275
279
  stream->print(',');
276
280
  #if defined(EEPROM_EMULATED)
277
281
  stream->print(EMULATED_EEPROM_LENGTH);
278
- #elif defined(EEPROM_PRESENT)
282
+ #elif defined(DENKO_EEPROM)
279
283
  stream->print(EEPROM.length());
280
284
  #endif
281
285
 
data/src/lib/Denko.h CHANGED
@@ -95,11 +95,13 @@ class Denko {
95
95
  void eepromRead (); //cmd = 7
96
96
  void eepromWrite (); //cmd = 8
97
97
 
98
- // Included Libraries
98
+ // Pulse inputs (DHT and HC-SR04)
99
99
  void pulseRead (); //cmd = 9
100
+ void hcsr04Read (); //cmd = 20
101
+
102
+ // Servos
100
103
  void servoToggle (); //cmd = 10
101
104
  void servoWrite (); //cmd = 11
102
- void handleSerial (); //cmd = 12
103
105
 
104
106
  // Single Bit Bang UART
105
107
  #ifdef DENKO_UART_BB
@@ -134,9 +134,24 @@
134
134
  // Best performance acknowledging at 64 bytes, or 32 if buffer is only 64.
135
135
  //
136
136
  // These are 256/64 regardless of whether native USB CDC or UART bridge.
137
- #if defined(ARDUINO_ARCH_RP2040) || defined(ESP32) || defined(ESP8266) || defined(__SAM3X8E__)
137
+ #if defined(ARDUINO_ARCH_RP2040) || defined(ESP8266) || defined(__SAM3X8E__)
138
138
  #define DENKO_SERIAL_BUFFER_SIZE 256
139
139
  #define DENKO_RX_ACK_INTERVAL 64
140
+ // ESP32 defaults to 256 buffer. Stay one under.
141
+ #elif defined(ESP32)
142
+ #define DENKO_SERIAL_BUFFER_SIZE 255
143
+ #ifdef ARDUINO_USB_CDC_ON_BOOT
144
+ // S2 unreliable with acknowledgement before buffer is full.
145
+ #ifdef CONFIG_IDF_TARGET_ESP32S2
146
+ #define DENKO_RX_ACK_INTERVAL 255
147
+ // S3 and C3 are fine acknowledging at half buffer filled.
148
+ #else
149
+ #define DENKO_RX_ACK_INTERVAL 128
150
+ #endif
151
+ // Default to 64 if using a UART bridge.
152
+ #else
153
+ #define DENKO_RX_ACK_INTERVAL 64
154
+ #endif
140
155
  // RA4M1 has a 512 Serial buffer.
141
156
  #elif defined(_RENESAS_RA_)
142
157
  #define DENKO_SERIAL_BUFFER_SIZE 512
@@ -31,7 +31,7 @@ void Denko::showLEDArray() {
31
31
 
32
32
  // ATmega4809 still needs this delay to avoid corrupt data. Not sure why.
33
33
  #if defined(__AVR_ATmega4809__)
34
- delayMicroseconds(64);
34
+ microDelay(64);
35
35
  #endif
36
36
 
37
37
  // Write the pixel buffer to the array.