Fireplace: LCD to display approximate propane usage and cost - persist variables?

I have created a simple Relay Switch that turns my milliwatt propane fireplace ON/OFF using Argon, a remote control or Apple’s Homekit or by a button on a Xenon. It works great, It’s pretty cool, but I also got a big propane bill this month. To reduce that I’d like to make the cost more visible to the family and hopefully change behaviors (ahem) of leaving the fireplace on for long periods of time. Pardon my nasty code - I’m new to coding in general.

I would like to create a small LCD display that:

  • counts how many minutes the fireplace has been on
  • after being turned on - auto turns off after 60mins
  • Can display the dollar amount of propane used this ‘session’
  • Display the total dollar amount spent since I reset it

The propane ‘measurement’ will simply be me calibrating the propane usage of the fireplace by watching the gas meter for an hour - then using that approximate value to count how many gallons is used per hour. Don’t worry, there will be no direct monitoring of propane gas.

I’d like the LCD to update every minute or so and Display something like:


Run time: 23min Cost: $1.23
Total Spent (since reset): $27.49


I’ve tried to read up on millis(), timer(), and other related approaches - and I think I’ll need to do something like the following:

  • Have a simple server that can capture how many minutes/gallons are used in one session so that value can persist across particle reboots, etc. I probably need to update that every minute it runs?
    Likely using webhooks to pass a variable via GET
    ** Persist the current market price of Propane (which i will manually update)
    ** Allow me to reset the total usage counter by blanking out the stored value
  • Modify my current code to have a timer for 60 minutes that turns off after it has been first started (call a function which acts as a toggle for the fire)
  • Retrieve the values from my server (Total_Minutes, Propane_price) every minute and then update the LCD
    ** Session Cost will be calculated on the device using the Propane_Cost value from my server

I realize:

  • If i change the price at some point - ALL the previous recorded hours will be priced according to the new price. That’s OK, I’ll probably reset it when I change the price.
  • Session is not persistent on reset, but every minute the particle will update total time on my server, so I’m not worried about “losing” much time.

Questions:

  • How should I setup the timer in my code. I’m confused. I’m pretty sure Delay() is useless here
  • Do I use webhooks to get the data back from the server?
int fire_switch = D0;
int remote_sensor = D2;
int homekit_state;

int MAIN_STATUS;

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int remote_state = 0;         // current state of the button
int lastRemote_state = 0;     // previous state of the button

void setup() {

pinMode(fire_switch, OUTPUT);
digitalWrite(fire_switch,HIGH);
pinMode(remote_sensor, INPUT_PULLDOWN);


Particle.function("fireplace",fireToggle);
Particle.function("hktogg",hktoggle);

Particle.variable("MAIN_STATUS", MAIN_STATUS);


Particle.subscribe("Button_change", xenon_handler);
Particle.subscribe("hook-response/minute_used", myHandler, MY_DEVICES);
}




void loop() {
    
    
    remote_state = digitalRead(remote_sensor);
    Particle.variable("remote_state", remote_state);
    
    
    // compare the buttonState to its previous state
  if (remote_state != lastRemote_state) {
    // if the state has changed, increment the counter
    if (remote_state == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Particle.publish("button Change","on");
      Particle.publish("number of button pushes:", String(buttonPushCounter));
      Particle.variable("PushCounter",String(buttonPushCounter));
      fireToggle("1");
    } else {
      // if the current state is LOW then the button went from on to off:
      Particle.publish("button Change","off");
      fireToggle("0");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastRemote_state = remote_state;

    
    
    /*
   if (remote_state == 1)
    {
      // Fire should be ON
      fireToggle("1");
      // Particle.publish("Loop 1", "Toggle ON");
      delay(100);
    }
    else if (remote_state == 0)
    {
      fireToggle("0");
      // Particle.publish("Loop 2", "Toggle OFF");
      delay(100);
    }
    
    // Particle.publish("LOOP", String(remote_state));
    
    */

    delay(200);
    
}


int hktoggle(String command) {

 if (command=="1") {     // Turn ON
        delay(100);
       fireToggle("1");
       Particle.publish("Homekit:", "ON");
        
        return 1;
    }
    
    else if (command=="0") {   // turn off
       fireToggle("0");
       Particle.publish("Homekit:", "OFF");
        return 0;
    }
  
    else if (command=="?"){   // check state
        
        if (MAIN_STATUS==1) {     // Currently On
        Particle.publish("Homekit Status:", "ON");
        return 1;
        }
    
        else if (MAIN_STATUS==0) {   // Currently off
            Particle.publish("Homekit Status:", "OFF");
            return 0;
        }
        
    }  
            
    else {
        return -1;
    }



}



void xenon_handler(const char *event, const char *data)
{
fireToggle(data);
}







int fireToggle(String command) {
    /* Spark.functions always take a string as an argument and return an integer.
    Since we can pass a string, it means that we can give the program commands on how the function should be used.
    In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
    Then, the function returns a value to us to let us know what happened.
    In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
    and -1 if we received a totally bogus command that didn't do anything to the LEDs.
    */



    if (command=="1") {     // Turn ON
        
        digitalWrite(fire_switch,LOW);
        delay(100);
        MAIN_STATUS=1;
        Particle.publish("Firetoggle:", String("Turned On"));
        Particle.publish("minute_used", "1", PRIVATE);
       
        
        return 1;
    }
    
    else if (command=="0") {   // turn off
        digitalWrite(fire_switch,HIGH);
        Particle.publish("Firetoggle:", String("Turned Off"));
        MAIN_STATUS=0;
        return 0;
    }
  
            
    else {
        return -1;
    }
    
    
}


Any help or constructive suggestions are appreciated!

Persisting variables over resets: have a look at EEPROM.
You can still push it to something like Google sheets so you can make nice graphs and everything.

Have a look at single shot software timers. Alternatively, millis() counters.
Or a timer library.

Most likely. It depends on whether or not it’s critical that the data is available over a longer period of time. You could use EEPROM to store the data on the device, and do everything locally. It’s only when data points become too frequent to fit, that you’ll need to outsource.

Also, there’s most likely also a gas price API available somewhere which you could query for up-to-date pricing. Multiply and add. That way, any pricing updates won’t change old values. That, or store the price with timestamps.

Just my $0.02 :slight_smile:

1 Like