Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
John R McAlpine V Mac
Published

Particle Weather VFD

A retro VFD weather display project powered by Weather Underground and Particle.

IntermediateShowcase (no instructions)1 hour2,049
Particle Weather VFD

Things used in this project

Hardware components

Photon
Particle Photon
×1
MAX232 Serial Level converter
×1
IEE Serial VFD Display IEE 05464-35118-01
×1

Story

Read more

Code

PARTICLE Photon Code

Arduino
VFD Weather Display Code
SYSTEM_THREAD(ENABLED);

int rssival = 0;

// Define the pins we're going to call pinMode on
int led = D3;  // You'll need to wire an LED to this one to see it blink.
int led2 = D7; // This one is the built-in tiny one to the right of the USB jack
int vfdhandler(String command);
int vfdwaitflag = 0;

double analog1 = 0;
double analog2 = 0;
double analog3 = 0;
double analog4 = 0;
double analog5 = 0;
double analog6 = 0;
double analog7 = 0;
double analog8 = 0;

double analog1raw = 0;
double analog2raw = 0;
double analog3raw = 0;
double analog4raw = 0;
double analog5raw = 0;
double analog6raw = 0;
double analog7raw = 0;
double analgo8raw = 0;
//char *ip = "no habla IP address ";


const char vfdnocursorconst = 0x0E;
const char vfderaseconst = 0x15;
const char vfdhomeconst = 0x16;
const char vfdmvcursorconst = 0x1B;
const char vfdbright = 0x30;
//char publishString[40];
//char data[125];
char txbuff[64];
//const String cityLocation = "Cornelius";  //City for my Photon
const String stationid = "KNCCORNE10";     // weather station ID for my Photon

SYSTEM_MODE(SEMI_AUTOMATIC); //allows for control of Spark.connect() and Spark.process()

//Timer intervaltimer(100, intervaltask);
Timer wxintervaltimer(300000, wxintervaltask);
Timer sparkfuncintervaltimer(10000, sparkfuncintervaltask);

// This routine runs only once upon reset
void setup() {

//...
    // Initialize D0 + D7 pin as output
    // It's important you do this here, inside the setup() function rather than outside it or in the loop function.
    Serial.begin(230400);  //open serial for debugging
    pinMode(led, OUTPUT);
    pinMode(led2, OUTPUT);
    pinMode(A0, INPUT);
    //digitalWrite(A0,0);
    Serial1.begin(19200);   // open serial for the display
    vfdnocursor();
    vfderase();
    //ip = {"IP:", WiFi.localIP()};
    //String ip = WiFi.localIP();

    Spark.function("vfdprint", vfdhandler);
    Spark.function("vfdctrl", vfdcontrol);
    Particle.subscribe("hook-response/current_weather", wxHandler, MY_DEVICES);
    
    pinMode(A0, INPUT_PULLDOWN);
    pinMode(A1, INPUT_PULLDOWN);
    pinMode(A2, INPUT_PULLDOWN);
    pinMode(A3, INPUT_PULLDOWN);
    pinMode(A4, INPUT_PULLDOWN);
    pinMode(A5, INPUT_PULLDOWN);
    pinMode(A6, INPUT_PULLDOWN);
    pinMode(A7, INPUT_PULLDOWN);
    digitalWrite(A0,1);
}

void loop() {
    if (Spark.connected() == false){
        //intervaltimer.stop();
        wxintervaltimer.stop();
        sparkfuncintervaltimer.stop();
        //vfderase();
        vfdmvcursor(0);
        Serial1.print(" Yo from PARTICLE! ");
        vfdmvcursor(20);
        Serial1.print("  Connecting");
        Serial.println("Connecting:");  //print to usb
        //Serial1.print("SSID: ");
        //Serial1.print(WiFi.SSID());
        Spark.connect();
        vfdwait(35,1);
        
        
    } 
    
    else {
        
        vfderase();
        Serial1.print(" I found a way out. ");
        
        vfdmvcursor(20);    
        Serial1.print("                    ");
        vfdmvcursor(20);    
        Serial1.print("SSID: ");
        Serial1.print(WiFi.SSID());
        Serial.print("SSID: "); //print to usb
        Serial.println(WiFi.SSID());  //print to usb
        vfdwait(39,2);
        
        vfdmvcursor(20);
        Serial1.print("IP: ");
        Serial1.print(WiFi.localIP());
        Serial.print("IP: ");
        Serial.println(WiFi.localIP());
        
        vfdwait(39,2);
        
        vfdmvcursor(20);    
        Serial1.print("                    ");
        vfdmvcursor(20);    
        Serial1.print("RSSI: ");  
        Serial1.print(WiFi.RSSI());
        Serial.print("RSSI: ");  //print to usb
        Serial.println(WiFi.RSSI());  //print to usb
        vfdwait(39,2);
        vfderase();
        
        wxintervaltask();
        //intervaltimer.start();
        wxintervaltimer.start();
        //sparkfuncintervaltimer.start();
        
        
        while (Spark.connected()){  //main system loop when connected
            
            if (System.buttonPushed() > 500) {
                wxintervaltask();
            }
            
            Spark.process();
            
            analog1raw = analogRead(A0);
            analog1 = (analog1 *63 +analog1raw *20.0/4095)/64;
            //analog1 = (analog1*10.0 + analog1raw)/11.0;
            // calibrate pot such that 12.00V in is 1.961V at micro.
            
            analog2raw = analogRead(A1);
            analog2 = (analog1 *63 +analog1raw *20.0/4095)/64;
            
            analog3raw = analogRead(A2);
            analog3 = (analog3 *63 +analog3raw *20.0/4095)/64;
            
        }
        
    }
 // delay(1000);
}
void sparkfuncintervaltask(){
    Serial.println(".");
/*
    rssival = WiFi.RSSI();
    sprintf(publishString,"%d",rssival);
    
    Spark.publish("RSSI",publishString);
    Serial.print("RSSI:");
    Serial.println(publishString);
*/
}

void wxintervaltask(){
    //String publishString = "{\"my-city\": \"" + cityLocation + "\", \"my-state\": \"" + stateLocation + "\" }";
    Serial.println("Running webook query current_weather:");
    
    String publishString = "{\"stationid\": \"" + stationid + "\"}";

    Particle.publish("current_weather", publishString, PRIVATE);
    vfdwait(39,2);
}

void wxHandler(const char *event, const char *data) {
    Serial.println("Receiving wxhandler subscribe data:");

    //Serial.println(data);
    
    //data = data.remove(40);
    
    Serial.println(data);
    String str = String(data);
    char strBuffer[64] = "";
    str.toCharArray(strBuffer, 64); // example: "\"21~99~75~0~22~98~77~20~23~97~74~10~24~94~72~10~\""
    
    //{{#response}}{{#current_observation}}{{#estimated}}{{weather}}~{{temp_f}}~{{relative_humidity}}~{{wind_dir}}~{{wind_gust_mph}}~{{dewpoint_f}}~{{/estimated}}{{/current_observation}}{{/response}}
    
    /*
   Serial.println("Running gotweatherData function");
    String str = String(data);
    char strBuffer[500] = "";
    str.toCharArray(strBuffer, 500); // example: \"Clear~78.8~24%~NORTH~3.36~360~\",
    */
    
    String weatherState = strtok(strBuffer, "\"~");
    //float currentTemp = atof(strtok(NULL, "~"));
    String currentTemp = strtok(NULL, "~");
    String humidity = strtok(NULL, "~");
    String windDir = strtok(NULL, "~");
    String windSpeed = String(atoi(strtok(NULL, "~"))); //convert from string float to integer then back to string to eliminate fractional wind speed
    String dewPoint = strtok(NULL, "~");
    
    /*
    float maxtemp = atof(strtok(NULL, "~"));
    int mainHumidity = atoi(strtok(NULL, "~"));
    int maxwind = atoi(strtok(NULL, "~"));
    float windDeg = atof(strtok(NULL, "~"));
    uint32_t sunrise = atoi(strtok(NULL, "~"));
    uint32_t sunset = atoi(strtok(NULL, "~"));
    String weatherName = strtok(NULL, "~");
  */  
   Serial.print("WeatherState: ");
   Serial.println(weatherState);
   Serial.print("CurrentTemp: ");
   Serial.println(currentTemp);
   Serial.print("Humidity: ");
   Serial.println(humidity);
   Serial.print("WindDir: ");
   Serial.println(windDir);
   Serial.print("WindSpeed: ");
   Serial.println(windSpeed);
   Serial.print("DewPoint: ");
   Serial.println(dewPoint);
    
    //delay(1000);
    while (vfdwaitflag==1) {
        delay(10);
    }
    
    vfderase();
    //standard print raw string
    //Serial1.print(str.remove(40));  //print weather data to VFD
    vfdmvcursor(0);
    Serial1.print(weatherState);
    vfdmvcursor(14);
    Serial1.print(currentTemp);
    Serial1.print("F");
    vfdmvcursor(20);
    Serial1.print(humidity);
    vfdmvcursor(24);
    Serial1.print(windDir);
    vfdmvcursor(30);
    //Serial1.print(dewPoint);
    vfdmvcursor(38);
    Serial1.print("  ");
    vfdmvcursor(34);
    Serial1.print(windSpeed);
    Serial1.print("mph");
    
    digitalWrite(led2, !digitalRead(led2));  //toggle led

    /*
    if (forecastday1 == Time.day()) {
      currentFcastday = forecastday1;
      currentFcastmax = maxtempday1;
      currentFcastmin = mintempday1;
      currentFcastwind = maxwindday1;
      Serial.print("Selected forecastday1");
    }
    if (forecastday2 == Time.day()){
        currentFcastday =forecastday2;
        currentFcastmax = maxtempday2;
        currentFcastmin = mintempday2;
        currentFcastwind = maxwindday2;
        Serial.print("Selected forecastday2");
      }
    bool weatherGood = true;
    */
    int updateweatherhour = Time.hour();
    
}
          



void intervaltask() {
                digitalWrite(led, !digitalRead(led));   // Turn ON the LED pins
                digitalWrite(led2, !digitalRead(led2));
                vfdmvcursor(0); //move cursor to position 0,0 home
                //Serial1.print(data);
                
                Serial1.print("  -=PARTICLE=-  ");
                Serial1.print(WiFi.RSSI());
                Serial1.print(" ");
                vfdmvcursor(20);
                Serial1.print("    Volts: ");
                //Serial1.print(WiFi.RSSI());
                
                Serial1.print(analog1, 4);
                Serial1.print("  ");
                Serial.print("ana");
                Serial.print(analog1raw, 0);
                Serial.print(" ");
                Serial.print(analog2, 0);
                Serial.print(" ");
                Serial.print(analog3, 0);
                Serial.print(" ");
                Serial.print(analog4, 0);
                Serial.print(" ");
                Serial.print(analog5, 0);
                Serial.print(" ");
                Serial.print(analog6, 0);
                Serial.print(" ");
                Serial.print(analog7, 0);
                Serial.print(" ");
                Serial.println(analog8, 0);
                
}

void vfdnocursor() {
  Serial1.write(vfdnocursorconst); 
}

void vfdhome() {
    Serial1.write(vfdhomeconst); 
}

void vfderase() {
  Serial1.write(vfderaseconst); 
  delay(2);
}

void vfdmvcursor(int cursorloc) {

  Serial1.write(vfdmvcursorconst);
  Serial1.write(cursorloc); //move cursor to line 1,0 line 2 
  delay(1); 
}

void vfdwait(int cursorloc, int loops) {
vfdwaitflag = 1;
char* spinner[] = {"-","\\","|","/","-","\\","|","/"};
    for (int i=0; i<loops; i++){ 
        if (Spark.connected() == false){
            Spark.process();
        }
        for (int j=0; j<8; j++) {
            vfdmvcursor(cursorloc);
            Serial1.write(spinner[j]);
            /*timeElapsed = 0;
            while (timeElapsed< interval){
                if (Spark.connected() == false){
                    Spark.process();
                }                
            }
            */
            delay(100);
            //if (Spark.connected() == false){
            //        Spark.process();
            //}
        }
        
    }
vfdwaitflag = 0;
}

int vfdhandler(String vfdstring){
    vfderase();
    Serial1.print(vfdstring);
    vfdwait(39,5);
    return 1;
    
}

int vfdcontrol(String vfdstring){
int x;
char* bytecmd;
int brightness;
char* charbuffer[60];

  brightness = vfdstring.charAt(0) - '0';
  if (brightness< 0 || brightness >7) return -1;
  delay(2);
  //vfdstring.getBytes(charbuffer, vfdstring);
  Serial1.write(0x31); 
  Serial1.write(0xFF);
  Serial1.write(brightness);
  delay(2);
 
    return 1;
    
}

/*example json webhook
{
	"event": "current_weather",
	"url": "http://api.wunderground.com/api/YOUR-KEY-HERE/conditions/q/pws:{{stationid}}.json",
	"requestType": "POST",
	"headers": null,
	"query": null,
	"responseTemplate": "{{#response}}{{#current_observation}}{{#estimated}}{{weather}}~{{temp_f}}~{{relative_humidity}}~{{wind_dir}}~{{wind_gust_mph}}~{{dewpoint_f}}~{{/estimated}}{{/current_observation}}{{/response}}",
	"responseTopic": "hook-response/current_weather",
	"json": null,
	"auth": null,
	"mydevices": true
}
*/


/*
00h Null 4.6 Miscellaneous Codes
01h Prepare to Read Display Identification 4.4 Prepare to Read Codes
02h Prepare to Read Software Check sum 4.4 Prepare to Read Codes
03h Prepare to Read Cursor Location 4.4 Prepare to Read Codes
04h Prepare to Read Data at Cursor Location 4.4 Prepare to Read Codes
05h Prepare to Read Data at Cursor Location and Increment 4.4 Prepare to Read Codes
06h Unassigned
07h Bell/Alarm Output 4.6 Miscellaneous Codes
08h Backspace Cursor 4.2 Cursor Control Codes
09h Advance Cursor 4.2 Cursor Control Codes
0Ah Line Feed 4.2 Cursor Control Codes
0Bh Blink Block Cursor 4.2 Cursor Control Codes *
0Ch Underbar Cursor 4.2 Cursor Control Codes *
0Dh Carriage Return 4.2 Cursor Control Codes
0Eh Cursor Off 4.2 Cursor Control Codes
0Fh Cursor On 4.2 Cursor Control Codes
10h Scroll Line Lock 4.6 Miscellaneous Codes
11h Set Vertical Scroll Mode 4.3 Data Display Codes
12h Unassigned
13h Set Horizontal Scroll Mode 4.3 Data Display Codes
14h Software Reset 4.6 Miscellaneous Codes
15h Clear Display and Home Cursor 4.2 Cursor Control Codes
16h Home Cursor 4.2 Cursor Control Codes
17h Set Data Bit 7 High 4.6 Miscellaneous Codes
18h Begin User Defined Character 4.3 Data Display Codes
19h Set Address Bit 0 High 4.6 Miscellaneous Codes
1Ah Cursor up One Line 4.2 Cursor Control Codes
1Bh Move Cursor to Designated Location 4.2 Cursor Control Codes
1Ch Select European Character Set 4.3 Data Display Codes
1Dh Select Katakana Character Set 4.3 Data Display Codes
1Eh Select Cyrillic 4.3 Data Display Codes
1Fh Select Hebrew Character Set 4.3 Data Display Codes
30h Set Display Screen or Column Brightness Level 4.5 Screen Control Codes
31h Begin Blinking Character(s) 4.5 Screen Control Codes
32h End Blinking Character(s) 4.5 Screen Control Codes
33h Blank Display Screen 4.5 Screen Control Codes
34h Unblank Display Screen 4.5 Screen Control Codes
+35h Comma/Period/Triangle Function 4.5 Screen Control Codes
36h Erase Line data With End Blink 4.5 Screen Control Codes
37h Set Carriage Return and Line Feed Definitions 4.5 Screen Control Codes
38h Underbar On 4.2 Cursor Control Codes *
39h Underbar Off 4.2 Cursor Control Codes *
3Ah Select Right to Left Data Entry 4.5 Screen Control Codes
3Bh Select Left to Right Data Entry 4.5 Screen Control Codes
3Ch Screen Saver On 4.5 Screen Control Codes
3Dh Screen Saver Off 4.5 Screen Control Codes
3Eh Execute Self–test 4.6 Miscellaneous Codes
3Fh Terminate Self–test 4.6 Miscellaneous Codes
*/

Particle Webhook Code

JSON
{
	"event": "current_weather",
	"url": "http://api.wunderground.com/api/YOUR-API-KEY-HERE/conditions/q/pws:{{stationid}}.json",
	"requestType": "POST",
	"headers": null,
	"query": null,
	"responseTemplate": "{{#response}}{{#current_observation}}{{#estimated}}{{weather}}~{{temp_f}}~{{relative_humidity}}~{{wind_dir}}~{{wind_gust_mph}}~{{dewpoint_f}}~{{/estimated}}{{/current_observation}}{{/response}}",
	"responseTopic": "hook-response/current_weather",
	"json": null,
	"auth": null,
	"mydevices": true
}

Credits

John R McAlpine V Mac
17 projects • 87 followers
www.MACSBOOST.com Assistant Teaching Professor at UNC Charlotte MEGR3171 Instrumentation, Motorsports Research

Comments