Register / Login  |  Desktop view  |  Jump to bottom of page

tcMenu Arduinio library » Securing Submenus with EEPROM

Author: jonboy545
31/03/2020 15:25:06
Been trying to get this to work for hours, I feel like I'm missing something minor, but not sure what to do.
EEPROM is working fine for saving parameters.

Tried to snip only necessary parts for below.

I have this in my include area:
#include <EepromAbstraction.h>
#include <ArduinoEEPROMAbstraction.h>
AvrEeprom eeprom;
EepromAuthenticatorManager eepromAuth;
const unsigned int authRomStart = 800;


In my void setup:
menuMgr.load(eeprom);  // Load default EEPROM values
  // EEPROM Authentication
  eepromAuth.initialise(&eepromAbstraction, authRomStart);
  remoteServer.setAuthenticator(&eepromAuth);
  menuMgr.setAuthenticator(&authManager);


The submenu that I have checked to secure in the DesignerUI is "SubMenuItem menuConfigurationTechnicianSettings;"




I'm getting a compile error "eepromAbstraction was not declared in this scope".

Where is this variable supposed to be setup? Am I missing an Include?

Author: davetcc
31/03/2020 15:33:53
I'm on my phone at the moment, but I think I see it...

If you look in the top snippet of code, you've named the AvrEeprom variable "eeprom".

However, in the lower snippet, you are referrring to it as "eepromAbstraction". Change that to "eeprom" as it's referring to the AvrEeprom you declared earlier.

Try that and see if it compiles.

Author: jonboy545
31/03/2020 16:00:02
Thank you Dave! Got it compiled as follows:

In header

#include <EepromAbstraction.h>
#include <ArduinoEEPROMAbstraction.h>
AvrEeprom eeprom;
EepromAuthenticatorManager eepromAuth;
const unsigned int authRomStart = 50;



In void setup()

// EEPROM Authentication
  eepromAuth.initialise(&eeprom, authRomStart);
  menuMgr.setAuthenticator(&eepromAuth);


Now I'm not getting the designerUi to actually secure the submenu.

If I check the box for securing the submenu, then save, the checkbox reverts back to unchecked.
If I generate code before saving, I can't tell that anything actually changes in the files, and submenu isn't secured.

Thank you so much for your help!

Author: jonboy545
31/03/2020 16:05:55
Actually appears not even saving, just navigating away from the selected submenu (to a different submenu) causes the checkbox to revert to unchecked.

I can get around this, if I knew what is changed in the files generated and just enter the value(s) manually. I'm guessing something in "NAME_menu.h" changes?

Author: davetcc
31/03/2020 16:09:58
Just for now, before the call to setupMenu() in the sketch setup function add:

menuConfigurationTechnicianSettings.setSecured(true);


This works because to secure a menu, you can do it yourself as well using the following method on the menu item object:

void setSecured(bool secured)


Please can you send me the version of the designer you are using and the platform you're running it on?

Author: jonboy545
31/03/2020 17:31:00
App & API 1.3.5
Build Date 2019-11-09 07:31
TcMenu Version 1.3.5
IoAbstraction Version 1.4.10
LiquidCrystalO Version 1.1.0

Windows 10 Home 64 Bit

Author: davetcc
31/03/2020 17:40:44
All on the latest version, so the must be a bug in the designer. I'll get that tested and try to reproduce shortly.

Did the fix I suggested work temporarily until the bug in the designer can be fixed?

BTW as an aside to this, for Win10 there's a new designer and control UI coming very soon that will be available from the Windows Store, probably within the next few weeks. It should work at least as well as the current one for most cases but is far more sustainable for us going forwards.

Author: jonboy545
31/03/2020 22:44:37
Yes sir! Worked fantastically.
Trying to write a password manager function, for changing password. Please keep in mind I have limited knowledge, so I'm learning as I go.

I'm trying to figure out how the password is stored in memory. I did an eeprom dump. My password starts at address 50, and I get this:
Memory Address: 50	50
Memory Address: 51	155
Memory Address: 52	0
Memory Address: 53	255
Memory Address: 54	255
Memory Address: 55	255
Memory Address: 56	255
Memory Address: 57	255
Memory Address: 58	255
Memory Address: 59	255
Memory Address: 60	255
Memory Address: 61	255
Memory Address: 62	255
Memory Address: 63	255
Memory Address: 64	255
Memory Address: 65	255
Memory Address: 66	255
Memory Address: 67	255
Memory Address: 68	0


Now I'm not sure if address 68 is something I've done in the past, or if that's the end of the memory needed for eeprom authentication manager.

Trying my hardest not to just ask everytime I have a question. Tried converting "1234" into hex, binary, etc and I'm not seeing the connection to 50 155 0.





Feel free to overlook, but if you want some cringe from a newbie, here's my sketch... Not anywhere done yet, not much free time. I'm sure there's.... quite alot.... that could use improvement/optimizing but hey... it's working so far.

Thank you again for a wonderful app/library/foundation. Looking forward to trying the new designerUI!

#include "Control_Board_Test_1_menu.h"
#include <EepromAbstraction.h>
#include <ArduinoEEPROMAbstraction.h>
AvrEeprom eeprom;
EepromAuthenticatorManager eepromAuth;
const unsigned int authRomStart = 50;  // Start locatin for eeprom authentication manager

// **** Callback Global Variables ****

// Inputs
  const int flowMeter1 = 40;  // For water flow, not used yet
  const int thermistor1 = A0; // Honeywell 10K thermistor
  const int thermistor2 = A1; // Honeywell 10k thermistor
  const int pressureSensor1 = A2;  // 0-16 bar. 5V supply. 10%min 90%max
  const int pressureSensor2 = A3;  // 0-16 bar. 5V supply. 10%min 90%max
  const int dispenseButton = 35;  // For automatic dosing, not used yet
  
// Outputs
  const int heater1 = 50;  // SSR output for service boiler
  const int heater2 = 51;  // SSR output for coffee boiler
  const int group1Solenoid = 52;  // Dispense solenoid relay, not used yet
  const int fillSolenoid = 53;  // Service boiler fill relay, not used yet
  bool serialEnableOut;

// **** Thermistor & Temperature Setup ****
  int Vo1, Vo2;
  int pullup1 = 10000;
  int pullup2 = 10000;
  float logR2_1, logR2_2, R2_1, R2_2, serviceBoilerTemp, coffeeBoilerTemp;
  float c1_1 = 1.009249522e-03, c2_1 = 2.378405444e-04, c3_1 = 2.019202697e-07;
  float c1_2 = 1.009249522e-03, c2_2 = 2.378405444e-04, c3_2 = 2.019202697e-07;

// **** Delay Variables Setup ****
  unsigned long now, now2 = millis();
  long lastMeasure, lastMeasure2 = 0;

// **** Flow Meter Setup ****
  int count1;  // Flowwmeter impulses
  float flowRate1;  // Flow-rate calculation

// **** Pressure Sensor Variables
  int boilerPressureRaw;  // Raw ADC value of pressure sensor
  float boilerPressure; // Converted pressure in bar
  int coffeePressureRaw;
  float coffeePressure;
  float maxServiceBoilerPressure = 2.0;
  float maxGroupPressure = 15.0;

// **** Brew Parameter Setup ****
  float preinfuseSec;  // Time to dispense without engaging pump, not used yet
  int impulse1, impulse2;  // Dosing impulses, not used yet
  int boilerTempCalibration;  // Change relative value of pullup resistor for calibrating thermistor
  int coffeeTempCalibration;  // Change relative value of pullup resistor for calibrating thermistor
  int serviceBoilerSetTemp;  // User programmable temperature of service boiler
  float coffeeBoilerSetTemp;  // User programmable temperature of coffee boiler/group head
  
// **** 4 Digit 7 Segment LED Screen Setup ****
  #include "SevenSegmentTM1637.h"
  #include "SevenSegmentExtended.h"
  const byte PIN_CLK = 32;   // TM1637 CLK pin
  const byte PIN_DIO = 33;   // TM1637 DIO pin
  SevenSegmentTM1637 display(PIN_CLK, PIN_DIO);
  int ledBrightness;  // User programmable brightness of LED screen

// **** Serial Debugging and EEPROM Dump ****
  int address;
  int addressMax = 100;  // Number of memory addresses to dump starting at 0
  byte value;
  int readSerialOutSpeed;  // For enable serial debugging, set message rate
  int serialOutSpeed;  // For enable serial debugging, set message rate
  
void setup() {
  Serial.begin(115200);
  // EEPROM Authentication
  eepromAuth.initialise(&eeprom, authRomStart);
  menuMgr.setAuthenticator(&eepromAuth);
  menuConfigurationTechnicianSettings.setSecured(true);  // Secure "Technician Settings" sub-menu
  setupMenu();
  menuMgr.load(eeprom);  // Load default EEPROM values  
  // Setup Inputs/Outputs
  pinMode(heater1, OUTPUT);  // Service Boiler SSR
  pinMode(heater2, OUTPUT);  // Coffee Boiler/Group Head SSR
  pinMode(group1Solenoid, OUTPUT);  // Dispense Solenoid Relay
  pinMode(fillSolenoid, OUTPUT);  // Service Boiler Relay
  pinMode(flowMeter1, INPUT);  // Flowmeter Input
  pinMode(dispenseButton, INPUT);  // Dispense Request Button
  pinMode(13, OUTPUT);  // Turn stupid onboard LED off!
  digitalWrite(13, LOW); // Turn stupid onboard LED off!
  // Ensure all outputs are off on boot
  digitalWrite(heater1, LOW);
  digitalWrite(heater2, LOW);
  digitalWrite(group1Solenoid, LOW);
  digitalWrite(fillSolenoid, LOW);
  // Flowmeter Interrupt, not used yet
  //attachInterrupt(0, flow1, CHANGE);
  display.begin();  //Start TM1637 LED Display
  // Display welcome on LED display.
  //display.setPrintDelay(150);
  //display.print("    WELCOME    ");
  // Bootup Serial Output
  Serial.println(F("Input Pins:"));
  Serial.print(F("Flow Meter 1: Pin "));
  Serial.println(flowMeter1);
  Serial.print(F("Steam Boiler Thermistor: Pin "));
  Serial.println(thermistor1);
  Serial.print(F("Coffee Boiler Thermistor: Pin "));
  Serial.println(thermistor2);
  Serial.print(F("Steam Boiler Pressure Sensor: Pin "));
  Serial.println(pressureSensor1);
   Serial.print(F("Coffee Boiler/Group Pressure Sensor: Pin "));
  Serial.println(pressureSensor2); 
  Serial.println(); 
  Serial.println(F("Output Pins:"));
  Serial.print(F("Fill Solenoid: Pin "));
  Serial.println(fillSolenoid);
  Serial.print(F("Group 1 Solenoid: Pin "));
  Serial.println(group1Solenoid);
  Serial.print(F("Boiler Heater 1: Pin "));
  Serial.println(heater1);
  Serial.print(F("Boiler Heater 2: Pin "));
  Serial.println(heater2);
  Serial.println();
  Serial.println();
  Serial.println(F("Enable Serial Debugging in Configuration/Technician Settings menu for input/output data"));
  Serial.println();
  Serial.println();
}

float mapFloat(float x, float in_min, float in_max, float out_min, float out_max)
{
 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// **** MENU CALLBACKS ****

void flow1() {  // Count flow-meter pulses, not used yet
  
}

void CALLBACK_FUNCTION preinfuseTime(int id) {  // Update pre-infuse time, not used yet
    
}

void CALLBACK_FUNCTION ledScreenBrightness(int id) {  // Change TM1637 LED Screen Brightness
  ledBrightness = menuConfigurationDisplaySettingsLEDBrightness.getCurrentValue();
  ledBrightness = map(ledBrightness, 0, 5, 10, 70);  // User selectable brightness of 0-5 scaled to 10%-70%
  display.setBacklight(ledBrightness);    
}

void CALLBACK_FUNCTION lcdBrightness(int id) {
    // TODO - your menu change code
}


void CALLBACK_FUNCTION heater1Test(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION ledScreenEnable(int id) {
    bool ledEnable = menuConfigurationDisplaySettingsEnableLEDDisp.getBoolean();
    if (ledEnable == true) {
      display.setBacklight(ledBrightness);
      return;
    }
    else {
      display.setBacklight(0);  // "Turn Off" LED screen by changing brightness to 0%
      return;
    }
}

void CALLBACK_FUNCTION groupSolenoidTest(int id) {
    // TODO - your menu change code
}


void CALLBACK_FUNCTION lcdContrast(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION heater2Test(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION preinfuseEnable(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION boilerTempAdjust(int id) {
    boilerTempCalibration = menuConfigurationTechnicianSettingsCalibrateSensorsBoilerTempAdjustCalibrationValue.getCurrentValue();
    pullup1 = map(boilerTempCalibration, 0, 10, 9000, 11000);
    menuConfigurationTechnicianSettingsCalibrateSensorsBoilerTempAdjustBoilerTemp.setFloatValue(serviceBoilerTemp, true);
}

void CALLBACK_FUNCTION coffeeTempAdjust(int id) {
    coffeeTempCalibration = menuConfigurationTechnicianSettingsCalibrateSensorsGroupTempAdjustCalibrationValue.getCurrentValue();
    pullup2 = map(coffeeTempCalibration, 0, 10, 9000, 11000);
    menuConfigurationTechnicianSettingsCalibrateSensorsGroupTempAdjustGroupTemp.setFloatValue(coffeeBoilerTemp, true);
}

void CALLBACK_FUNCTION setBoilerTemp(int id) {
    serviceBoilerSetTemp = menuConfigurationMachineSettingsServiceBoiler.getCurrentValue();
    //menuMgr.save(eeprom);
}

void CALLBACK_FUNCTION setCoffeeBoilerTemp(int id) {
    coffeeBoilerSetTemp = menuConfigurationMachineSettingsCoffeeBoiler.getCurrentValue();
    //menuMgr.save(eeprom);
}

void CALLBACK_FUNCTION saveSettings(int id) {
  menuMgr.save(eeprom);
}

void CALLBACK_FUNCTION pressureProfile2(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION pressureProfile3(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION pressureProfile1(int id) {
    // TODO - your menu change code
}

void CALLBACK_FUNCTION serialEnable(int id) {
  serialEnableOut = menuConfigurationTechnicianSettingsSerialDebuggingSerialOutput.getCurrentValue();
}

void CALLBACK_FUNCTION serialSpeed(int id) {
   readSerialOutSpeed = menuConfigurationTechnicianSettingsSerialDebuggingOutputSpeed.getCurrentValue();
   serialOutSpeed = map(readSerialOutSpeed, 0, 5, 5000, 1000);
   
}

// **** END CALLBACKS ****


// **** Serial Debug Output ****
void serialOutput() {
  Serial.print(F("Steam Boiler Set Temp:............... "));
  Serial.println(serviceBoilerSetTemp);
  Serial.print(F("Boiler Temperature:.................. "));
  Serial.println(serviceBoilerTemp);
  Serial.print(F("Boiler Heat On/Off:.................. "));
    if (serviceBoilerTemp <= serviceBoilerSetTemp) {
      Serial.println(F("ON"));
    }
    else {
      Serial.println(F("OFF"));
    }
  Serial.print(F("Coffee Boiler Set Temp:.............. "));
  Serial.println(coffeeBoilerSetTemp);
  Serial.print(F("Coffee Boiler Temp:.................. "));
  Serial.println(coffeeBoilerTemp);
  Serial.print(F("Coffee Heat On/Off:.................. "));
    if (coffeeBoilerTemp <= coffeeBoilerSetTemp) {
      Serial.println(F("ON"));
    }
    else {
      Serial.println(F("OFF"));
    }  
  Serial.println();
  Serial.print(F("Boiler Pressure Raw Value:........... "));
  Serial.println(boilerPressureRaw);
  Serial.print(F("Boiler Pressure BAR:................. "));
  Serial.println(boilerPressure, 2);
  Serial.println();    
  Serial.print(F("Coffee Pressure Raw Value:........... "));
  Serial.println(coffeePressureRaw);
  Serial.print(F("Coffee Pressure BAR:................. "));
  Serial.println(coffeePressure, 2);
  Serial.println(); 
  Serial.println();
  Serial.println(); 
  Serial.println();  
}

void CALLBACK_FUNCTION dumpEeprom(int id) {
  Serial.println(F("Memory allocation as follows:"));
  Serial.println(F("0-1 Fixed"));
  Serial.println(F("2-3 LCD Brightness"));
  Serial.println(F("4-5 LCD Contrast"));
  Serial.println(F("6-6 Serial Output Enabled"));
  Serial.println(F("7-8 Serial Output Speed"));
  Serial.println(F("9-10 LED Brightness"));
  Serial.println(F("11-12 Preinfuse Time"));
  Serial.println(F("13-13 Preinfuse Enable"));
  Serial.println(F("14-15 Service Boiler Temp Calibration Value"));
  Serial.println(F("16-17 Service Boiler Set Temp"));
  Serial.println(F("18-18 Enable LED Display"));
  Serial.println(F("20-21 Coffee Boiler Temp Calibration Value"));
  Serial.println(F("22-23 Coffee Boiler Set Temp"));
  Serial.println(F("24-25 Dose 1"));
  Serial.println(F("26-27 Dose 2"));
  Serial.println();
  Serial.println(F("50-68 Password Auth"));
  Serial.println();
  Serial.print(F("Dumping first "));
  Serial.print(addressMax);
  Serial.println(F(" locations in memory"));
  Serial.println(F("_______________________________________"));
  for (address = 0; address <= addressMax; address++) {
    value = EEPROM.read(address);
    Serial.print(F("Memory Address: "));
    Serial.print(address);
    Serial.print("\t");
    Serial.print(value, DEC);
    Serial.println();
  }
  Serial.println(F("_______________________________________"));
  Serial.println();
  Serial.println(F("Memory Dump Complete"));
}

// **** Main LOOP ****

void loop() {
  taskManager.runLoop();

  // **** Pressure Reading ASAP ****

  // Service/Steam Boiler
  boilerPressureRaw = analogRead(pressureSensor1);
  boilerPressure = mapFloat(boilerPressureRaw, 0.0, 1023.0, 0.0, 3.0); 
  menuBoilerPres.setCurrentValue((boilerPressure * 10), true);
  menuConfigurationTechnicianSettingsInputTestsBoilerPres.setCurrentValue((boilerPressure * 10), true);  

  // Group/Coffee Boiler
  coffeePressureRaw = analogRead(pressureSensor2);
  coffeePressure = mapFloat(coffeePressureRaw, 00.0, 1023.0, 0.0, 16.5);
  menuGroupPres.setCurrentValue((coffeePressure * 10), true);
  menuConfigurationTechnicianSettingsInputTestsGroupPres.setCurrentValue((coffeePressure * 10), true);
  
  
  // **** Thermistor Reading Every 1 Second ****
  now = millis();
  if (now - lastMeasure > 1000) {    // Only take temp reading ever XX seconds
    lastMeasure = now;
    Vo1 = analogRead(thermistor1);
    Vo2 = analogRead(thermistor2);
    R2_1 = pullup1 * (1023.0 / (float)Vo1 - 1.0);
    R2_2 = pullup2 * (1023.0 / (float)Vo2 - 1.0);
    logR2_1 = log(R2_1);
    logR2_2 = log(R2_2);
    serviceBoilerTemp = (1.0 / (c1_1 + c2_1*logR2_1 + c3_1*logR2_1*logR2_1*logR2_1));
    coffeeBoilerTemp = (1.0 / (c1_2 + c2_2*logR2_2 + c3_2*logR2_2*logR2_2*logR2_2));
    serviceBoilerTemp = serviceBoilerTemp - 273.15;
    coffeeBoilerTemp = coffeeBoilerTemp - 273.15;
    serviceBoilerTemp = (serviceBoilerTemp * 9.0)/ 5.0 + 32.0;
    coffeeBoilerTemp = (coffeeBoilerTemp * 9.0)/ 5.0 + 32.0;

    // **** Update Menu Screens with temp values ****
    menuConfigurationTechnicianSettingsCalibrateSensorsBoilerTempAdjustBoilerTemp.setFloatValue(serviceBoilerTemp, true);  // Updates menu data on temp calibration screen
    menuConfigurationTechnicianSettingsCalibrateSensorsGroupTempAdjustGroupTemp.setFloatValue(coffeeBoilerTemp, true);  // Updates menu data on temp calibration screen
    menuConfigurationTechnicianSettingsInputTestsGroupBoiler.setCurrentValue((coffeeBoilerTemp * 10), true);  // Updates Input Test Screen with Temp
    menuConfigurationTechnicianSettingsInputTestsServBoiler.setCurrentValue((serviceBoilerTemp * 10), true);  // Updates Input Test Screen with Temp 

    // Update LED Screen with temperatres, just for testing will find other purpose later
    display.setColonOn(true);
    display.setCursor(0, 0);
    display.print(serviceBoilerTemp, 0);
    display.setCursor(0, 2);
    display.print(coffeeBoilerTemp, 0);    
  }

  // **** Constant Loop Checks ****
  
  // Control Heaters
  if (boilerPressure > maxServiceBoilerPressure) {  // Safety check - Disable Steam Boiler if above max pressure;
    digitalWrite(heater1, LOW);
  }
    else {
      // To be replaced by a PID loop eventually...
      if (serviceBoilerTemp <= (serviceBoilerSetTemp - 1)) {  // Turn on steam boiler SSR if temp is less than set temp 
        digitalWrite(heater1, HIGH);
      }
        else if(serviceBoilerTemp >= (serviceBoilerSetTemp + 1)){
          digitalWrite(heater1, LOW);
        }
    }
  if (coffeePressure > maxGroupPressure) {  // Safety check - Disable Coffee Boiler if above 14 bar
    digitalWrite(heater2, LOW);
  }
    else {
      // To be replaced by a PID loop...
      if (coffeeBoilerTemp <= (coffeeBoilerSetTemp - 1)) {  // Turn on coffee boiler SSR if temp is less than set temp 
        digitalWrite(heater2, HIGH);
      }
        else if(coffeeBoilerTemp >= (coffeeBoilerSetTemp + 1)) {
          digitalWrite(heater2, LOW);
        }
    }

  // **** Serial Output - Speed controlled by config setting
  now2 = millis();
  if (now2 - lastMeasure2 > serialOutSpeed) {
    lastMeasure2 = now2;
    while (serialEnableOut == true) {
      serialOutput();
      break;
    }
  }
}
// **** END LOOP ****

Author: davetcc
01/04/2020 08:37:17
Sorry I've not had a chance to look over the sketch fully.

The way the EepromAuthenticatorManager works is that it initializes from EEPROM only if the magic key (you either provide or is defaulted) is in the ROM already. If it is not already in the ROM it defaults to 1234. It also stores 6 pairings with user name and UUID of remote connections there too, even if you are not using remote connectivity. You can lower this number if EEPROM storage is tight.

To change the pin / password, simply call changePin(newPin) on the EeepromAuthenticationManager. Usually, you'd do this from within a protected menu. Maybe create a text field to hold to replacement pin, and an action item to take the value and call changePin.

Also, in terms of all the code in loop doing timing, you know that taskManager is part of tcMenu, you can use that to schedule things to be done, once or at a repeated interval, take a look at the following:

https://www.thecoderscorner.com/products/arduino-libraries/io-abstraction/task-manager-scheduling-guide/




Register / Login  |  Desktop view  |  Jump to top of page