Implemented the calibration mode and introduced a 'height' value in the mqtt stream, which is (container height - distance measurement). First implementation, so much might still change. I'm thinking about introducing a virtual sensor, but I'm not sure yet what the cleanest implementation will look like.
This commit is contained in:
parent
e416dab9dd
commit
e48e44f287
130
src/App/App.cpp
130
src/App/App.cpp
|
@ -45,16 +45,8 @@ namespace Dough
|
||||||
|
|
||||||
void App::loop()
|
void App::loop()
|
||||||
{
|
{
|
||||||
if (!wifi.isConnected())
|
if (!_setupNetworking())
|
||||||
{
|
{
|
||||||
state.setWiFiConnected(false);
|
|
||||||
state.setWiFiConnected(wifi.connect());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mqtt.isConnected())
|
|
||||||
{
|
|
||||||
state.setMQTTConnected(false);
|
|
||||||
state.setMQTTConnected(mqtt.connect());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,33 +56,13 @@ namespace Dough
|
||||||
switch (state.get())
|
switch (state.get())
|
||||||
{
|
{
|
||||||
case CONFIGURING:
|
case CONFIGURING:
|
||||||
if (config.isOk())
|
_doConfigure();
|
||||||
{
|
|
||||||
state.startMeasurements();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MEASURING:
|
case MEASURING:
|
||||||
if (config.isOk())
|
_doMeasure();
|
||||||
{
|
|
||||||
if (temperatureController.loop())
|
|
||||||
distanceSensor.setTemperature(temperatureController.getLast().value);
|
|
||||||
if (humidityController.loop())
|
|
||||||
distanceSensor.setHumidity(humidityController.getLast().value);
|
|
||||||
distanceController.loop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.startConfiguration();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CALIBRATING:
|
case CALIBRATING:
|
||||||
temperatureController.loop();
|
_doCalibrate();
|
||||||
humidityController.loop();
|
|
||||||
distanceController.loop();
|
|
||||||
|
|
||||||
delay(2000);
|
|
||||||
state.pauseDevice();
|
|
||||||
state.startMeasurements();
|
|
||||||
break;
|
break;
|
||||||
case PAUSED:
|
case PAUSED:
|
||||||
temperatureController.clearHistory();
|
temperatureController.clearHistory();
|
||||||
|
@ -102,4 +74,98 @@ namespace Dough
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool App::_setupNetworking()
|
||||||
|
{
|
||||||
|
if (!wifi.isConnected())
|
||||||
|
{
|
||||||
|
state.setWiFiConnected(false);
|
||||||
|
state.setWiFiConnected(wifi.connect());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!mqtt.isConnected())
|
||||||
|
{
|
||||||
|
state.setMQTTConnected(false);
|
||||||
|
state.setMQTTConnected(mqtt.connect());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::_doConfigure()
|
||||||
|
{
|
||||||
|
if (config.isOk())
|
||||||
|
{
|
||||||
|
state.startMeasurements();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::_doMeasure()
|
||||||
|
{
|
||||||
|
if (config.isOk())
|
||||||
|
{
|
||||||
|
if (temperatureController.loop())
|
||||||
|
distanceSensor.setTemperature(temperatureController.getLast().value);
|
||||||
|
if (humidityController.loop())
|
||||||
|
distanceSensor.setHumidity(humidityController.getLast().value);
|
||||||
|
if (distanceController.loop())
|
||||||
|
mqtt.publish("height", config.getContainerHeight() - distanceController.getLast().value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.startConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::_doCalibrate()
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
int runningTotal = 0;
|
||||||
|
unsigned int firstValue = 0;
|
||||||
|
unsigned int precision = distanceController.getPrecision();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Read a sensor value. When this fails, then restart the calibration.
|
||||||
|
auto m = distanceController.readSensor();
|
||||||
|
if (!m.ok)
|
||||||
|
{
|
||||||
|
_logger.log("s", "Sensor reading failed, restarting calibration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_logger.log("sisis", "Calibration reading ", count, ": ", m.value, "mm");
|
||||||
|
|
||||||
|
count++;
|
||||||
|
runningTotal += m.value;
|
||||||
|
|
||||||
|
// If this is the first value that is read, then use that one to compare
|
||||||
|
// the upcoming measurements against.
|
||||||
|
if (count == 1)
|
||||||
|
{
|
||||||
|
firstValue = m.value;
|
||||||
|
}
|
||||||
|
// Otherwise, check if the new value is within the precision range of the
|
||||||
|
// distance sensor.
|
||||||
|
else if (abs(firstValue - m.value) > precision)
|
||||||
|
{
|
||||||
|
_logger.log("s", "New reading exceeds sensor precision, restarting calibration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After reading 10 values in a row that are within the sensor precision,
|
||||||
|
// then we have a winner.
|
||||||
|
if (count == 10)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.log("sis", "Calibration completed, container height: ", firstValue, "mm");
|
||||||
|
unsigned int container_height = int(runningTotal / 10);
|
||||||
|
config.setContainerHeight(container_height);
|
||||||
|
mqtt.publish("container_height", container_height, true);
|
||||||
|
|
||||||
|
state.pauseDevice();
|
||||||
|
state.startMeasurements();
|
||||||
|
}
|
||||||
} // namespace Dough
|
} // namespace Dough
|
|
@ -39,6 +39,10 @@ namespace Dough
|
||||||
private:
|
private:
|
||||||
App();
|
App();
|
||||||
Logger _logger;
|
Logger _logger;
|
||||||
|
bool _setupNetworking();
|
||||||
|
void _doConfigure();
|
||||||
|
void _doMeasure();
|
||||||
|
void _doCalibrate();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,30 +65,37 @@ namespace Dough
|
||||||
_mqttClient.subscribe(topic);
|
_mqttClient.subscribe(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MQTT::publish(const char *key, const char *payload)
|
void MQTT::publish(const char *key, const char *payload, bool retained)
|
||||||
{
|
{
|
||||||
char topic[200];
|
char topic[200];
|
||||||
snprintf(topic, sizeof(topic) / sizeof(topic[0]), "%s/%s/%s", MQTT_TOPIC_PREFIX, _mqttDeviceId, key);
|
snprintf(topic, sizeof(topic) / sizeof(topic[0]), "%s/%s/%s", MQTT_TOPIC_PREFIX, _mqttDeviceId, key);
|
||||||
_logger.log("ssss", "Send message: ", topic, " = ", payload);
|
_logger.log("ssss", "Send message: ", topic, " = ", payload);
|
||||||
_mqttClient.publish(topic, payload);
|
if (retained)
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publish(const char *key, int payload)
|
|
||||||
{
|
|
||||||
char buf[16];
|
|
||||||
snprintf(buf, 16, "%d", payload);
|
|
||||||
publish(key, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publish(const char *key, Measurement measurement)
|
|
||||||
{
|
|
||||||
if (measurement.ok)
|
|
||||||
{
|
{
|
||||||
publish(key, measurement.value);
|
_mqttClient.publish(topic, payload, true, 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
publish(key, "null");
|
_mqttClient.publish(topic, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MQTT::publish(const char *key, int payload, bool retained)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
snprintf(buf, 16, "%d", payload);
|
||||||
|
publish(key, buf, retained);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MQTT::publish(const char *key, Measurement measurement, bool retained)
|
||||||
|
{
|
||||||
|
if (measurement.ok)
|
||||||
|
{
|
||||||
|
publish(key, measurement.value, retained);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
publish(key, "null", retained);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Dough
|
} // namespace Dough
|
|
@ -26,9 +26,9 @@ namespace Dough
|
||||||
bool connect();
|
bool connect();
|
||||||
void subscribe(const char *key);
|
void subscribe(const char *key);
|
||||||
void procesIncomingsMessages();
|
void procesIncomingsMessages();
|
||||||
void publish(const char *key, const char *payload);
|
void publish(const char *key, const char *payload, bool retained = false);
|
||||||
void publish(const char *key, int payload);
|
void publish(const char *key, int payload, bool retained = false);
|
||||||
void publish(const char *key, Measurement measurement);
|
void publish(const char *key, Measurement measurement, bool retained = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger _logger;
|
Logger _logger;
|
||||||
|
|
|
@ -19,6 +19,11 @@ namespace Dough
|
||||||
return sensor->getName();
|
return sensor->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int SensorController::getPrecision()
|
||||||
|
{
|
||||||
|
return sensor->getPrecision();
|
||||||
|
}
|
||||||
|
|
||||||
void SensorController::setup()
|
void SensorController::setup()
|
||||||
{
|
{
|
||||||
sensor->setup();
|
sensor->setup();
|
||||||
|
@ -41,24 +46,24 @@ namespace Dough
|
||||||
{
|
{
|
||||||
_plugin->beforeMeasure(this);
|
_plugin->beforeMeasure(this);
|
||||||
_lastMeasuredAt = millis();
|
_lastMeasuredAt = millis();
|
||||||
_store(sensor->read());
|
_store(readSensor());
|
||||||
_plugin->afterMeasure(this);
|
_plugin->afterMeasure(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto last = getLast();
|
|
||||||
|
|
||||||
if (_mustPublish())
|
if (_mustPublish())
|
||||||
{
|
{
|
||||||
_plugin->beforePublish(this);
|
_plugin->beforePublish(this);
|
||||||
|
auto last = getLast();
|
||||||
auto average = getAverage();
|
auto average = getAverage();
|
||||||
_lastPublishedAt = millis();
|
_lastPublishedAt = millis();
|
||||||
average.copyTo(&_lastPublishedAverage);
|
average.copyTo(&_lastPublishedAverage);
|
||||||
last.copyTo(&_lastPublished);
|
last.copyTo(&_lastPublished);
|
||||||
_plugin->doPublish(this, last, average);
|
_plugin->doPublish(this, last, average);
|
||||||
_plugin->afterPublish(this);
|
_plugin->afterPublish(this);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return last.ok;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SensorController::_mustMeasure()
|
bool SensorController::_mustMeasure()
|
||||||
|
@ -162,6 +167,11 @@ namespace Dough
|
||||||
return _index;
|
return _index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Measurement SensorController::readSensor()
|
||||||
|
{
|
||||||
|
return sensor->read();
|
||||||
|
}
|
||||||
|
|
||||||
Measurement SensorController::getLast()
|
Measurement SensorController::getLast()
|
||||||
{
|
{
|
||||||
return *_storage[_index];
|
return *_storage[_index];
|
||||||
|
|
|
@ -60,10 +60,13 @@ namespace Dough
|
||||||
// Return the name for the contained sensor.
|
// Return the name for the contained sensor.
|
||||||
const char *getSensorName();
|
const char *getSensorName();
|
||||||
|
|
||||||
|
// Return the measuring precision for the contained sensor.
|
||||||
|
unsigned int getPrecision();
|
||||||
|
|
||||||
// Read the sensor and publish the results when needed.
|
// Read the sensor and publish the results when needed.
|
||||||
// This method returns true when the last read value was an ok measurement.
|
// This method returns true when the last read value was an ok measurement
|
||||||
// This means that after this method returns true, getLast() will return
|
// and a publish operation was done. This means that after this method returns
|
||||||
// an ok Dough::Measurement.
|
// true, getLast() will return an ok Dough::Measurement.
|
||||||
bool loop();
|
bool loop();
|
||||||
|
|
||||||
// Read a measurement from the sensor.
|
// Read a measurement from the sensor.
|
||||||
|
|
Loading…
Reference in New Issue