Skip to content

Commit

Permalink
Added control mode
Browse files Browse the repository at this point in the history
  • Loading branch information
matzeema committed Jun 18, 2022
1 parent dd4d065 commit a31912c
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 50 deletions.
2 changes: 1 addition & 1 deletion ArduinoPool/ArduinoPool.ino
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void loop() {
if (systemState == SYSTEM_STATE_OFF) {
Serial.println("Pool control is deactivated by server.");
setArduinoPoolState(NO_ERRORS_STATE);
} else if (systemState == SYSTEM_STATE_NO_ERRORS) {
} else {
for (int i = 0; i < 5; i++) {
float temp = getTempInC();
if ((temp > TEMP_UNABLE_LOW) && (temp < TEMP_UNABLE_HIGH)) {
Expand Down
38 changes: 25 additions & 13 deletions ArduinoPump/ArduinoPump.ino
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void loop() {
Serial.println("'Read system state' max reached. Try reconnecting to Wifi...");
disablePump();
setArduinoPumpState(FAILED_READ_SYSTEM_STATE);

if (reconnectToWifi() < 0) {
Serial.println("Failed reconnecting to Wifi!");
} else {
Expand All @@ -65,24 +65,36 @@ void loop() {
Serial.println("Pool control is system-wide off.");
disablePump();
setArduinoPumpState(NO_ERRORS_STATE);
} else if (systemState == SYSTEM_STATE_NO_ERRORS) {
bool arduinoPoolReachable = checkArduinoPoolLastConnection();
} else {

if (!arduinoPoolReachable) {
Serial.println("ArduinoPool not reachable. Disableing pump.");
int mode = getControlMode();
Serial.print("Control mode: ");
Serial.println(mode);
if (mode == CONTROL_MODE_ALWAYS_ON) {
activatePump();
setArduinoPumpState(NO_ERRORS_STATE);
} else if (mode == CONTROL_MODE_ALWAYS_OFF) {
disablePump();
setArduinoPumpState(TEMP_DATA_OUTDATED);
setArduinoPumpState(NO_ERRORS_STATE);
} else {
double poolTemp = getPoolTemperature();
double requestedTemp = getRequestedTemperature();

if (poolTemp <= -127.0 || requestedTemp <= -127.0) {
Serial.println("Failed reading temperatures from server.");
bool arduinoPoolReachable = checkArduinoPoolLastConnection();
if (!arduinoPoolReachable) {
Serial.println("ArduinoPool not reachable. Disableing pump.");
disablePump();
setArduinoPumpState(FAILED_READ_TEMP);
setArduinoPumpState(TEMP_DATA_OUTDATED);
} else {
controlPump(poolTemp, requestedTemp);
setArduinoPumpState(NO_ERRORS_STATE);
double poolTemp = getPoolTemperature();
double requestedTemp = getRequestedTemperature();

if (poolTemp <= -127.0 || requestedTemp <= -127.0) {
Serial.println("Failed reading temperatures from server.");
disablePump();
setArduinoPumpState(FAILED_READ_TEMP);
} else {
controlPump(poolTemp, requestedTemp);
setArduinoPumpState(NO_ERRORS_STATE);
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions ArduinoPump/Firebase.ino
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ double getRequestedTemperature(void) {
return getTemperatureFromFB(requestedTemperaturePath + "temperature", -127.0);
}

int getControlMode(void) {
return getIntFromFB(requestedTemperaturePath + "control-mode", -1);
}

unsigned long long getArduinoPoolLastConnection(void) {
return getTimestampFromFB(arduinoPoolPath + "last-connection");
}
Expand Down
4 changes: 4 additions & 0 deletions ArduinoPump/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
#define READ_SYSTEM_STATE_TRYS_MAX 5
#define RESET_FIREBASE_TRYS_MAX 5

#define CONTROL_MODE_AUTOMATIC 0
#define CONTROL_MODE_ALWAYS_ON 1
#define CONTROL_MODE_ALWAYS_OFF 2

#define DATA_TO_OLD_DIF 3660000
53 changes: 46 additions & 7 deletions geha_pool_webapp/lib/providers/db_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -228,48 +228,65 @@ class PumpData {
}

const _REQTEMP_LAST_UPDATE_KEY = "last-update";
const _REQTEMP_CONTROL_MODE_KEY = "control-mode";
const _REQTEMP_TEMPERATURE_KEY = "temperature";
const _REQTEMP_UPDATE_UID_KEY = "update-uid";

const MIN_TEMP = 0;
const MAX_TEMP = 40;

/// Temperature the requested temp is set to, when user wants to disable the pump.
/// Should be way under normal temperature values.
const _PUMP_DISABLED_TEMP = -100;
enum ControlMode {
automatic,
alwaysOn,
alwaysOff,
}

ControlMode _controlModeByInt(int? state) {
if (state == null) return ControlMode.automatic;
return ControlMode.values[state];
}

class ReqTempData {
ReqTempData(this._dbRef);

DatabaseReference _dbRef;
int? _lastUpdate;
int? _temperature;
int? _controlMode;

DateTime? get lastUpdate => _dateTimeByIntTimestamp(_lastUpdate);
String? get lastUpdateFormatted => _dateTimeFormatted(lastUpdate);
int? get temperature => _temperature;
ControlMode get controlMode => _controlModeByInt(_controlMode);

@deprecated
bool? get active => temperature != null ? temperature! >= MIN_TEMP : null;

void _setFromJSON(Map<String, dynamic> json) {
_lastUpdate = json[_ARPUMP_LAST_UPDATE_KEY];
_lastUpdate = json[_REQTEMP_LAST_UPDATE_KEY];
_temperature = json[_REQTEMP_TEMPERATURE_KEY];
_controlMode = json[_REQTEMP_CONTROL_MODE_KEY];
}

Future<bool> setTemperature(UserProvider users, int temperature) async {
if (!users.isSignedIn) {
throw StateError("Temperature can only be changed when logged in.");
print("Temperature can only be changed when logged in.");
return false;
}
if (temperature > MAX_TEMP) {
throw ArgumentError("Requested temperature must be <= $MAX_TEMP.");
print("Requested temperature must be <= $MAX_TEMP.");
return false;
}
if (temperature < MIN_TEMP) {
temperature = _PUMP_DISABLED_TEMP;
print("Requested temperature must be >= $MIN_TEMP.");
return false;
}

try {
final timestamp = DateTime.now().millisecondsSinceEpoch;
await _dbRef.update({
_REQTEMP_LAST_UPDATE_KEY: timestamp,
_REQTEMP_CONTROL_MODE_KEY: ControlMode.automatic.index,
_REQTEMP_TEMPERATURE_KEY: temperature,
_REQTEMP_UPDATE_UID_KEY: users.user!.uid,
});
Expand All @@ -279,6 +296,26 @@ class ReqTempData {
return true;
}

Future<bool> setControlMode(UserProvider users, ControlMode mode) async {
if (!users.isSignedIn) {
print("Control mode can only be changed when logged in.");
return false;
}

try {
final timestamp = DateTime.now().millisecondsSinceEpoch;
await _dbRef.update({
_REQTEMP_LAST_UPDATE_KEY: timestamp,
_REQTEMP_CONTROL_MODE_KEY: mode.index,
_REQTEMP_UPDATE_UID_KEY: users.user!.uid,
});
} catch (_) {
print(_);
return false;
}
return true;
}

void _onDbDataUpdated(Event event) {
final key = event.snapshot.key;
final value = event.snapshot.value;
Expand All @@ -287,6 +324,8 @@ class ReqTempData {
_lastUpdate = value;
} else if (key == _REQTEMP_TEMPERATURE_KEY) {
_temperature = value;
} else if (key == _REQTEMP_CONTROL_MODE_KEY) {
_controlMode = value;
}
}
}
8 changes: 5 additions & 3 deletions geha_pool_webapp/lib/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Strings {
static String get requestedTemperature => _STRINGS['requested_temperature']!;
static String get noRequestedTemperature =>
_STRINGS['no_requested_temperature']!;
static String get changeTemperature => _STRINGS['change_temperature']!;
static String get change => _STRINGS['change']!;
static String get logIn => _STRINGS['log_in']!;
static String get email => _STRINGS['email']!;
static String get password => _STRINGS['password']!;
Expand All @@ -41,6 +41,7 @@ class Strings {
static String get failedReadingSysStatePump =>
_STRINGS['failed_reading_sys_state_pump']!;
static String get tryAgain => _STRINGS['try_again']!;
static String get manualMode => _STRINGS['manual_mode']!;
}

const _STRINGS = {
Expand All @@ -55,7 +56,7 @@ const _STRINGS = {
"system_is_in_maintenance": "Das System ist in Wartung.",
"requested_temperature": "Wunschtemperatur",
"no_requested_temperature": "Keine Wunschtemperatur festgelegt.",
"change_temperature": "Temperatur ändern",
"change": "Ändern",
"log_in": "Anmelden",
"email": "E-Mail:",
"password": "Passwort:",
Expand All @@ -82,5 +83,6 @@ const _STRINGS = {
"Da der System-Status nicht gelesen werden kann, wird die Temperatur nicht aktualisiert.",
"failed_reading_sys_state_pump":
"Da der System-Status nicht gelesen werden kann, wurde die Pumpe deaktiviert.",
"try_again": "Erneut versuchen"
"try_again": "Erneut versuchen",
"manual_mode": "Manueller Modus",
};
62 changes: 44 additions & 18 deletions geha_pool_webapp/lib/widgets/change_temperature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,57 @@ class ChangeTemperatureDialog extends StatefulWidget {
}

class _ChangeTemperatureDialogState extends State<ChangeTemperatureDialog> {
int? temperature;
static const controlModeOffPoint = (MIN_TEMP - 1);
static const controlModeOnPoint = (MAX_TEMP + 1);

int? sliderPoint;
bool failedUpdating = false;

void updateTemperature(ReqTempData reqTemp) async {
if (temperature != null) {
if (await reqTemp.setTemperature(widget.userProvider, temperature!)) {
Navigator.pop(context);
void updateReqTemperature(ReqTempData reqTemp) async {
if (sliderPoint != null) {
final mode = controlModeBySliderPoint;
if (mode == ControlMode.automatic) {
if (await reqTemp.setTemperature(widget.userProvider, sliderPoint!)) {
Navigator.pop(context);
} else {
setState(() => failedUpdating = true);
}
} else {
setState(() => failedUpdating = true);
if (await reqTemp.setControlMode(widget.userProvider, mode)) {
Navigator.pop(context);
} else {
setState(() => failedUpdating = true);
}
}
}
}

ControlMode get controlModeBySliderPoint {
if (this.sliderPoint! >= controlModeOnPoint) return ControlMode.alwaysOn;
if (this.sliderPoint! <= controlModeOffPoint) return ControlMode.alwaysOff;
return ControlMode.automatic;
}

String get temperatureText {
if (controlModeBySliderPoint == ControlMode.alwaysOn) return "ON";
if (controlModeBySliderPoint == ControlMode.alwaysOff) return "OFF";
return "$sliderPoint°C";
}

@override
Widget build(BuildContext context) {
return Consumer<DbProvider>(
builder: (context, dbProvider, child) {
final reqTemp = dbProvider.reqTempData;
if (temperature == null) {
if (reqTemp.temperature == null) {
temperature = 20;
} else {
reqTemp.active!
? temperature = reqTemp.temperature
: temperature = (MIN_TEMP - 1);
if (sliderPoint == null) {
if (reqTemp.controlMode == ControlMode.alwaysOff) {
sliderPoint = controlModeOffPoint;
} else if (reqTemp.controlMode == ControlMode.alwaysOn) {
sliderPoint = controlModeOnPoint;
} else if (reqTemp.controlMode == ControlMode.automatic) {
reqTemp.temperature == null
? sliderPoint = 20
: sliderPoint = reqTemp.temperature;
}
}

Expand All @@ -68,17 +94,17 @@ class _ChangeTemperatureDialogState extends State<ChangeTemperatureDialog> {
Padding(
padding: const EdgeInsets.all(24.0),
child: Text(
this.temperature! >= MIN_TEMP ? "$temperature°C" : "OFF",
temperatureText,
style: Theme.of(context).textTheme.headline4,
),
),
Slider(
value: temperature!.toDouble(),
value: sliderPoint!.toDouble(),
onChanged: (newTemp) {
setState(() => temperature = newTemp.round());
setState(() => sliderPoint = newTemp.round());
},
min: (MIN_TEMP - 1).toDouble(),
max: MAX_TEMP.toDouble(),
max: (MAX_TEMP + 1).toDouble(),
),
Text(
Strings.setRequestedTemperature,
Expand Down Expand Up @@ -107,7 +133,7 @@ class _ChangeTemperatureDialogState extends State<ChangeTemperatureDialog> {
child: Text(Strings.cancel),
),
TextButton(
onPressed: () => updateTemperature(reqTemp),
onPressed: () => updateReqTemperature(reqTemp),
child: Text(Strings.save),
),
],
Expand Down
18 changes: 10 additions & 8 deletions geha_pool_webapp/lib/widgets/dashboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,17 @@ class ReqTemp extends StatelessWidget {
final ReqTempData reqTemp;

String get tempText {
if (reqTemp.temperature == null) {
return Strings.noRequestedTemperature;
}
if (!reqTemp.active!) {
return "< 0°C";
}
if (reqTemp.temperature == null) return Strings.noRequestedTemperature;
if (reqTemp.controlMode == ControlMode.alwaysOff) return "OFF";
if (reqTemp.controlMode == ControlMode.alwaysOn) return "ON";
return "${reqTemp.temperature}°C";
}

String get subtitleTempText {
if (reqTemp.controlMode != ControlMode.automatic) return Strings.manualMode;
return Strings.requestedTemperature;
}

void changeTemperature(BuildContext context) {
showDialog(context: context, builder: (context) => ChangeTemperature());
}
Expand All @@ -158,7 +160,7 @@ class ReqTemp extends StatelessWidget {
Padding(
padding: const EdgeInsets.only(top: 2.0, bottom: 6.0),
child: Text(
Strings.requestedTemperature,
subtitleTempText,
style: Theme.of(context).textTheme.bodyText1,
textAlign: TextAlign.center,
),
Expand All @@ -167,7 +169,7 @@ class ReqTemp extends StatelessWidget {
padding: const EdgeInsets.only(top: 6.0, bottom: 12.0),
child: MaterialButton(
onPressed: () => changeTemperature(context),
child: Text(Strings.changeTemperature),
child: Text(Strings.change),
textColor: Colors.blue,
),
),
Expand Down

0 comments on commit a31912c

Please sign in to comment.