Skip to content

Commit

Permalink
Power down and up strain when not in use etc. (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlhampuswall authored Jun 23, 2024
1 parent 35b9cd1 commit b8e93be
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 68 deletions.
136 changes: 77 additions & 59 deletions firmware/src/root_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,58 +396,16 @@ void RootTask::run()

// wake up the screen
// RangeStatus is usually 0,2,4. We want to caputure the level of confidence 0 and 2.
// Add motor encoder detection? or disable motor if not "enaged detected presence"
if (app_state.proximiti_state.RangeStatus < 3 && app_state.proximiti_state.RangeMilliMeter < 200)
{
app_state.screen_state.has_been_engaged = true;
if (app_state.screen_state.awake_until < millis() + KNOB_ENGAGED_TIMEOUT_NONE_PHYSICAL) // If half of the time of the last interaction has passed, reset allow for engage to be detected again.
{
app_state.screen_state.awake_until = millis() + KNOB_ENGAGED_TIMEOUT_NONE_PHYSICAL;
}
}
}
if (app_state.screen_state.has_been_engaged == true)
{
app_state.screen_state.brightness = app_state.screen_state.MAX_LCD_BRIGHTNESS;
if (app_state.screen_state.awake_until < millis())
{
app_state.screen_state.awake_until = millis() + 4000; // 1s
}
}
// Check if the knob is awake, and if the time is expired
// and set it to not engaged
if (app_state.screen_state.has_been_engaged && millis() < app_state.screen_state.awake_until)
{
app_state.screen_state.has_been_engaged = false;
}
#if SK_ALS
// We are multiplying the current luminosity of the enviroment (0,1 range)
// by the MIN LCD Brightness. This is for the case where we are not engaging with the knob.
// If it's very dark around the knob we are dimming this to 0, otherwise we dim it in a range
// [0, MIN_LCD_BRIGHTNESS]
uint16_t targetLuminosity = static_cast<uint16_t>(round(latest_sensors_state_.illumination.lux_adj * app_state.screen_state.MIN_LCD_BRIGHTNESS));

if (app_state.screen_state.has_been_engaged == false &&
abs(app_state.screen_state.brightness - targetLuminosity) > 500 && // is the change substantial?
millis() > app_state.screen_state.awake_until)
{
if ((app_state.screen_state.brightness < targetLuminosity))
{
app_state.screen_state.brightness = (targetLuminosity);
}
else
{
// TODO: I don't like this decay function. It's too slow for delta too small
app_state.screen_state.brightness = app_state.screen_state.brightness - ((app_state.screen_state.brightness - targetLuminosity) / 8);
}
}
else if (app_state.screen_state.has_been_engaged == false && (abs(app_state.screen_state.brightness - targetLuminosity) <= 500))
{
// in case we have very little variation of light, and the screen is not engaged, make sure we stay on a stable luminosity value
app_state.screen_state.brightness = (targetLuminosity);
}
#endif
#if !SK_ALS
if (app_state.screen_state.has_been_engaged == false)
{
app_state.screen_state.brightness = app_state.screen_state.MAX_LCD_BRIGHTNESS;
}
#endif

if (xQueueReceive(connectivity_status_queue_, &latest_connectivity_state_, 0) == pdTRUE)
{
Expand All @@ -466,6 +424,7 @@ void RootTask::run()
mqtt_task_->unlock();
#endif
}

if (xQueueReceive(knob_state_queue_, &latest_state_, 0) == pdTRUE)
{

Expand All @@ -479,6 +438,10 @@ void RootTask::run()
// We set a flag on the object Screen State.
// Todo: this property should be at app state and not screen state
app_state.screen_state.has_been_engaged = true;
if (app_state.screen_state.awake_until < millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL / 2) // If half of the time of the last interaction has passed, reset allow for engage to be detected again.
{
app_state.screen_state.awake_until = millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL; // stay awake for 4 seconds after last interaction
}
}
}
isCurrentSubPositionSet = true;
Expand All @@ -500,6 +463,40 @@ void RootTask::run()
break;
}

#if SK_ALS
// We are multiplying the current luminosity of the enviroment (0,1 range)
// by the MIN LCD Brightness. This is for the case where we are not engaging with the knob.
// If it's very dark around the knob we are dimming this to 0, otherwise we dim it in a range
// [0, MIN_LCD_BRIGHTNESS]
uint16_t targetLuminosity = static_cast<uint16_t>(round(latest_sensors_state_.illumination.lux_adj * app_state.screen_state.MIN_LCD_BRIGHTNESS));

if (app_state.screen_state.has_been_engaged == false &&
abs(app_state.screen_state.brightness - targetLuminosity) > 500 && // is the change substantial?
millis() > app_state.screen_state.awake_until)
{
if ((app_state.screen_state.brightness < targetLuminosity))
{
app_state.screen_state.brightness = (targetLuminosity);
}
else
{
// TODO: I don't like this decay function. It's too slow for delta too small
app_state.screen_state.brightness = app_state.screen_state.brightness - ((app_state.screen_state.brightness - targetLuminosity) / 8);
}
}
else if (app_state.screen_state.has_been_engaged == false && (abs(app_state.screen_state.brightness - targetLuminosity) <= 500))
{
// in case we have very little variation of light, and the screen is not engaged, make sure we stay on a stable luminosity value
app_state.screen_state.brightness = (targetLuminosity);
}
#endif
#if !SK_ALS
if (app_state.screen_state.has_been_engaged == false)
{
app_state.screen_state.brightness = app_state.screen_state.MAX_LCD_BRIGHTNESS;
}
#endif

#if SK_MQTT
mqtt_task_->enqueueEntityStateToSend(entity_state_update_to_send);
#endif
Expand All @@ -515,23 +512,31 @@ void RootTask::run()

current_protocol_->loop();

// std::string *log_string;
// while (xQueueReceive(log_queue_, &log_string, 0) == pdTRUE)
// {
// // LOGI(log_string->c_str());
// delete log_string;
// }

motor_notifier.loopTick();
os_config_notifier_.loopTick();

updateHardware(app_state);
updateHardware(&app_state);

if (app_state.screen_state.has_been_engaged == true)
{
if (app_state.screen_state.brightness != app_state.screen_state.MAX_LCD_BRIGHTNESS)
{
app_state.screen_state.brightness = app_state.screen_state.MAX_LCD_BRIGHTNESS;
sensors_task_->strainPowerUp();
}

if (millis() > app_state.screen_state.awake_until)
{
app_state.screen_state.has_been_engaged = false;
sensors_task_->strainPowerDown();
}
}

delay(1);
}
}

void RootTask::updateHardware(AppState app_state)
void RootTask::updateHardware(AppState *app_state)
{
static bool pressed;
#if SK_STRAIN
Expand All @@ -540,9 +545,16 @@ void RootTask::updateHardware(AppState app_state)
{
switch (latest_sensors_state_.strain.virtual_button_code)
{

case VIRTUAL_BUTTON_SHORT_PRESSED:
if (last_strain_pressed_played_ != VIRTUAL_BUTTON_SHORT_PRESSED)
{
app_state->screen_state.has_been_engaged = true;
if (app_state->screen_state.awake_until < millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL / 2) // If half of the time of the last interaction has passed, reset allow for engage to be detected again.
{
app_state->screen_state.awake_until = millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL; // stay awake for 4 seconds after last interaction
}

LOGD("Handling short press");
motor_task_.playHaptic(true, false);
last_strain_pressed_played_ = VIRTUAL_BUTTON_SHORT_PRESSED;
Expand All @@ -552,6 +564,12 @@ void RootTask::updateHardware(AppState app_state)
case VIRTUAL_BUTTON_LONG_PRESSED:
if (last_strain_pressed_played_ != VIRTUAL_BUTTON_LONG_PRESSED)
{
app_state->screen_state.has_been_engaged = true;
if (app_state->screen_state.awake_until < millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL / 2) // If half of the time of the last interaction has passed, reset allow for engage to be detected again.
{
app_state->screen_state.awake_until = millis() + KNOB_ENGAGED_TIMEOUT_PHYSICAL; // stay awake for 4 seconds after last interaction
}

LOGD("Handling long press");

motor_task_.playHaptic(true, true);
Expand Down Expand Up @@ -643,7 +661,7 @@ void RootTask::updateHardware(AppState app_state)
uint16_t brightness = UINT16_MAX;
// TODO: brightness scale factor should be configurable (depends on reflectivity of surface)
#if SK_ALS
brightness = app_state.screen_state.brightness;
brightness = app_state->screen_state.brightness;
#endif

#if SK_DISPLAY
Expand All @@ -662,7 +680,7 @@ void RootTask::updateHardware(AppState app_state)
// if 2: led ring is fully off.
// if 3: we have 1 led on as beacon (also refered as lighthouse in other part of the code).

if (brightness > app_state.screen_state.MIN_LCD_BRIGHTNESS)
if (brightness > app_state->screen_state.MIN_LCD_BRIGHTNESS)
{
// case 1. FADE-IN led
effect_settings.effect_id = 4; // FADE-IN
Expand All @@ -675,7 +693,7 @@ void RootTask::updateHardware(AppState app_state)
effect_settings.effect_main_color = (0 << 16) | (128 << 8) | 128;
led_ring_task_->setEffect(effect_settings);
}
else if (brightness == app_state.screen_state.MIN_LCD_BRIGHTNESS)
else if (brightness == app_state->screen_state.MIN_LCD_BRIGHTNESS)
{
// case 2. FADE-OUT led
effect_settings.effect_id = 5;
Expand Down
2 changes: 1 addition & 1 deletion firmware/src/root_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class RootTask : public Task<RootTask>
uint32_t last_calib_state_sent_ = 0;

// void changeConfig(int8_t id);
void updateHardware(AppState app_state);
void updateHardware(AppState *app_state);
void publishState();
void applyConfig(PB_SmartKnobConfig config, bool from_remote);
void publish(const AppState &state);
Expand Down
80 changes: 72 additions & 8 deletions firmware/src/sensors/sensors_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ void SensorsTask::run()
strain.tare();
delay(100);

strain_powered = true;
raw_initial_value_ = strain.get_units(10);
#endif

Expand Down Expand Up @@ -98,6 +99,7 @@ void SensorsTask::run()
unsigned long last_illumination_check_ms = 0;

unsigned long log_ms = 0;
unsigned long log_ms_strain = 0;

const uint8_t proximity_poling_rate_hz = 20;
const uint8_t strain_poling_rate_hz = 120;
Expand Down Expand Up @@ -125,7 +127,7 @@ void SensorsTask::run()
long last_system_temperature_check = 0;
float last_system_temperature = 0;

bool do_strain = false;
uint8_t discarded_strain_reading_count = 0;

while (1)
{
Expand All @@ -152,20 +154,19 @@ void SensorsTask::run()
#if SK_STRAIN
if (millis() - last_strain_check_ms > 1000 / strain_poling_rate_hz)
{
if (strain.wait_ready_timeout(100))
if (strain_powered && strain.wait_ready_timeout(100))
{
if (weight_measurement_step_ != 0 || factory_strain_calibration_step_ != 0)
{
delay(100);
do_strain = false;
}

if (calibration_scale_ == 1.0f && strain.get_scale() == 1.0f && factory_strain_calibration_step_ == 0)
{
LOGI("Strain sensor needs Factory Calibration, press 'Y' to begin!");
delay(2000);
do_strain = false;
}
else if (weight_measurement_step_ != 0 || factory_strain_calibration_step_ != 0)
{
delay(100);
do_strain = false;
}

if (do_strain)
{
Expand All @@ -174,12 +175,27 @@ void SensorsTask::run()

if (abs(last_strain_reading_raw_ - strain_reading_raw) > 2000)
{
discarded_strain_reading_count++;
if (discarded_strain_reading_count > 20)
{
LOGV(PB_LogLevel_WARNING, "Resetting strain sensor. 20 consecutive readings discarded.");
strain.power_down();
delay(100);
strain.power_up();
delay(100);
strain.set_offset(0);
strain.tare();
delay(100);
discarded_strain_reading_count = 0;
}

LOGW("Discarding strain reading, too big difference from last reading.");
LOGV(PB_LogLevel_WARNING, "Current raw strain reading: %f", strain_reading_raw);
LOGV(PB_LogLevel_WARNING, "Last raw strain reading: %f", last_strain_reading_raw_);
}
else
{
discarded_strain_reading_count = 0;
sensors_state.strain.raw_value = strain_filter.addSample(strain_reading_raw);

// LOGD("Strain raw reading: %f", sensors_state.strain.raw_value);
Expand Down Expand Up @@ -261,8 +277,22 @@ void SensorsTask::run()
last_strain_check_ms = millis();
}
}

do_strain = true;
}
else
{
if (do_strain && strain_powered && millis() - log_ms_strain > 4000)
{
LOGV(PB_LogLevel_DEBUG, "Strain sensor not ready, waiting...");
log_ms_strain = millis();
}
else if (millis() - log_ms_strain > 4000)
{
LOGV(PB_LogLevel_DEBUG, "Strain sensor is disabled. (Might be because of factory calib or its powered off because no engagement of knob)");
log_ms_strain = millis();
}
}
}
#endif

Expand Down Expand Up @@ -381,6 +411,8 @@ void SensorsTask::factoryStrainCalibrationCallback(float calibration_weight)
{
LOGE("Calibrated weight is more than 10g off from the calibration weight. Restart calibration by pressing 'Y' again.");
delay(2000);
strain.set_scale(1.0f);
calibration_scale_ = 1.0f;
factory_strain_calibration_step_ = 0;
return;
}
Expand Down Expand Up @@ -438,6 +470,38 @@ void SensorsTask::weightMeasurementCallback()
weight_measurement_step_ = 0;
}
}

void SensorsTask::strainPowerDown()
{
if (strain.wait_ready_timeout(10)) // Make sure sensor is on before powering down.
{
LOGV(PB_LogLevel_DEBUG, "Strain sensor power down.");

strain_powered = false;
strain.power_down();
}
}

void SensorsTask::strainPowerUp() // Delays caused a perceived delay in the activation of strain.
{
if (!strain.wait_ready_timeout(10)) // Make sure sensor is off before powering up.
{
LOGV(PB_LogLevel_DEBUG, "Strain sensor power up.");

strain.power_up();
if (strain.wait_ready_timeout(100))
{
strain.set_offset(0);
strain.tare();
last_strain_reading_raw_ = strain.get_units(10);
strain_powered = true;
}
else
{
LOGE("Strain sensor not ready after power up!!!");
}
}
}
#endif

void SensorsTask::addStateListener(QueueHandle_t queue)
Expand Down
Loading

0 comments on commit b8e93be

Please sign in to comment.