CSC270 Team 3 project 2019

From CSclasswiki
Jump to: navigation, search

Michelle Tsai Gomez and Christina Lyu's Serial Weather

Introduction

For our project will gather information from the yweather module in Python through the Raspberry Pi. From this module we will get the current weather conditions and temperature.

With the information gathered we will load from the Raspberry Pi 3 and send it to the Arduino MEGA2560 (ELEGOO brand) which will be connected to LEDs and display both the temperature in Celsius and Fahrenheit and also an emoji that represents the weather conditions.

This project should be too hard to gather equipment for, the LED matrix that we need for the display are available from the lab's equipment, and then the rest should be included in the Arduino kit.

In order to accomplish this we are planning on working step by step. Firstly, we might get the Raspberry Pi to gather the information needed from the internet and have it print it. Then gradually adding in the serial communication and the LEDs. To test it we plan on giving different weather scenarios to the Raspberry Pi and make sure that the Arduino can properly display them all on the LEDs.

This project will be able to meet the museum requirement of sitting behind a glass door because there is no need of human interaction after it's been set up, if there happens to be a power failure we could find a way to make the programs start over by itself. As it informs people of the outside weather, it should also be visually interesting.

Hardware and Programming

For the most part we should be coding with Python for the Arduino and the Raspberry Pi.

Materials:

Libraries:

  • serial
  • time
  • PyOWM
  • pathlib

Sensors:

  • instead of general sensors, we are taking the input from the PyOWM python module

Original Proposal:

The current plan we have for the project is to follow through the instructables tutorial we found for the Raspberry Pi. After we get the weather module to work we will move onto getting the Arduino to correctly receive the information. Then we will slowly add on the visuals and LEDs to display the temperatures and the emojis.

We want first design dummy program to test that we can receive the information from the weather module correctly probably by printing the information we want to receive onto the Serial monitor. Then we want to design the LED circuits (determining which board will serve to display which part of the output) and test each number, letter and emoji with simple test programs to test each digit would light up alright. Then we want to parse the information into the output we want.

For our final project, we want to build a physical frame that will hold the LED boards together so that the outputs from the LED boards can be seen as one coherent board. We do not necessarily want to glue things together because we want the LED boards to be reusable for other projects as well.

To test that our project meets the expectations, we want to give it several possible scenarios. During the test, we would turn off the power on the Arduino and Raspberry Pi for a while and then turn it back on to make sure that the connection is still valid between the parts and the information is sent and correctly displayed on the LED boards. We will also want to make sure that the failure of one or several LED light on one or more LED boards would not cause the entire circuit to fail.

Updated Plan:

The plan we ended up going with was to first learn how the LEDs worked, considering we had never worked with the matrices before. After we got to figure out how the chain linked LED matrices, we wanted to create the images we needed for the final display such as the numbers, the negative sign, and the emojis for the weather status.

Once the visuals were all properly set up, we moved on to figure out the weather module and how to call from the library to get the information we needed. Then, after we got to print the desired information, we worked with the Raspberry Pi and the Arduino and implementing their serial connection, and also making the RPi startup the program at boot. Once we were able to make the Arduino receive the necessary data from the RPi, we got to displaying the information onto the LEDs.

To test that our project met the expectations, we gave it several possible scenarios. During the test, we turned off the power on the Arduino and Raspberry Pi for a while and then turn it back on to make sure that: 1) the program starts up by itself 2) the connection is still valid between the parts, 3) the information is properly sent, 4) it is correctly displayed on the LED boards. We also made sure that all of the different weather conditions we could come up with were being properly displayed onto the LEDs.

For the final display we hot glued two Arduino breadboards together to fit the chain-linked LEDs, and then also glued the RPi and Arduino to the ends of the boards.

Resources

A project we found that implements the main idea of our project:

  • https://www.instructables.com/id/Weather-Display-Using-Arduino-and-Raspberry-Pi/
    • A tutorial to make a serial communication between an RPi and an Arduino and display certain conditions onto an LCD display (instead LEDs which is what we plan to do).
    • Our project differs significantly from this project in a major way. Instead of displaying the temperature in Celsius and Fahrenheit on a digital board, our project attempts to use LED boards to light up certain proportions of the LED boards to show numbers and emojis.

We used the Serial Dot Matrix tutorial to chain link the LEDs.

We also used the link to get PyOWM API key.

We consulted with the PyOWM documentation.

Pathlib module allows us to identify the correct path to the Serial port in Arduino.

We have also used methods that allow us to connect the Arduino and the Raspberry Pi

We modified our /etc/rc.local to reboot Raspberry Pi.

Update

On April 18, 23, and 25, we spent the days learning how the LED matrices worked. Throughout the days we used a Serial Dot Matrix tutorial that taught us how to connect the LED's in a chain and how to make them display different things (because the whole first couple of days we struggled with not having the LED's display the same light pattern for all the matrices). The third day we tried to design basic code chunks to design and display the digits, letters and emojis that we are going to use in the final circuit. In our design, two and a half of the LED boards would display the temperature (for both temperatures, so 5 LEDs total for this part) and the last LED board will display an emoji.

Screen Shot 2019-05-10 at 11.34.53 AM.png
Wiring schematics



Team3Update2.jpg
Initial wiring of the LED chain


On April 26, we decided on a new python module (since the one we had previously found was not working) and attained the Weather API key we would use to gather the weather data from the internet. We got to the point of successfully displaying temperature on LED boards.

Team3Update3.jpeg
Temperature Display on LED


On April 27, we worked on making the Raspberry Pi run the program at boot and followed this Startup tutorial. We also worked on the serial connection between the Arduino and the Raspberry Pi by following this Serial connection tutorial.
On April 28, we spent our last day working together to debug the serial connection and LEDs to make sure that the relationship was working properly, and that the display was demonstrating the correct information.

Team3Update1.jpg
Final product

Result

The result project of ours is a weather station that displays the current temperature of Northampton, MA in both Celsius and Fahrenheit. It also displays a predefined emoji representing the current weather status. The weather information is retrieved from PyOWM. The display gets updated every 30 minutes to in case of sudden changes happening during the day.

To allow our project to be less wire-y and more qualified to be displayed within a museum, we centered the six LED boards and glued the Raspberry Pi and the Arduino to each side of the breadboard.

As we consider the realistic situations of Northampton in which the temperature could drop down to negative celsius in winter, to allow ample space for each section of the display and be able to separate the elements with spaces in between, we decided to use a total number of six LED boards.

By using six LED boards, the weather station is able to display whether from that are negative in celsius to 999 Fahrenheit. The weather status are distributed into categories and represented by adorable emojis designed such as drizzling and rainy days will both be represented by an umbrella emoji.

A picture of the physic implementation of our final project looks like the pictures below.

SerialWeatherImplementation.png
SerialWeatherImplementation2.png
Final Wiring of Serial Weather

A live demonstration of our working project displaying the weather in Northampton on April 29th.

SerialWeatherDemonstration1.jpeg
Demonstration of Finished Product

We can see that the display shows that the current weather then is 7C, 45F and foggy.

Python Code in Raspberry Pi

''' 
Project: Serial Weather
Participants: Christina Lyu & Michelle Tsai Gomez
Date Finished: May 9, 2019
Instructor: Dominique Thiebaut
Class: CSC 270
Project Description: 
  The project fetches weather information using pyowm module from the internet using the appropriate API key and location id that represents the city Smith College is in, Northampton, MA, United States
  The project displays the current weather in celcius and fahrenheit and the status of the weather as an emoji. The weather information is updated every 30 minutes to keep up with the most recent weather status in case of sudden changes
  The project will automatically start when plugged in and will automatically reopen when the power supply is temporarily cut off
'''

# import python libraries and modules
from pyowm import OWM
import serial
import time
import pathlib

# define weather function that retrieves weather information from the internet using pyowm
def fweather(serialPort):
    # we got the api key from https://home.openweathermap.org/users/sign_up 
    API_key = '447eea78c4a822f4eec1495ab95f9351'
    owm = OWM(API_key)
    # the location id is set because it is a constant representing the city of Northampton (as there are more than one Northamptons in US)
    loc_id = 4945819
    obs = owm.weather_at_id(loc_id)
    w = obs.get_weather()

    # open serial port connection with python and set it to the same pace as the Arduino
    s = serial.Serial(serialPort, 9600)

    # get information from the weather object (celcius, fahrenheit and weather status)
    cel = w.get_temperature(unit='celsius')
    celtemp = str(int(round(cel.get('temp')))) + 'C'
    celtemp = " " * (5 - len(celtemp)) + celtemp
    fah = w.get_temperature('fahrenheit')
    fahtemp = str(int(round(fah.get('temp')))) + 'F'
    fahtemp = " " * (5 - len(fahtemp)) + fahtemp
    status = w.get_status().encode()

    # we also get sunrise and sunset time to determine whether the place is during day or night to determine which emoji to use to when the status is "clear"
    risetime = w.get_sunset_time('iso')
    risetime = risetime.split(' ')[-1]
    risetime = risetime.split(':')[0]
    settime = w.get_sunrise_time('iso')
    settime = settime.split(' ')[-1]
    settime = settime.split(':')[0]   

    while True:
        # in an infinite loop, we want to keep sending a determined format to hold the information we retrieved with a 1 second interval until finding that the port connection has been set up
        s.write(celtemp + fahtemp + "|" + risetime + settime + status.lower())
        time.sleep(1)
        k = s.inWaiting()

        # when the port has been set up, we break out of the loop to avoid sending the same data more than once
        if k > 0:
            break

def main():
    # get the port name of the Arduino serial port that appears in the Pi directory
    currentDirectory = pathlib.Path('/dev')

    # define the pattern, the arduino serial port always starts with the following prefix
    currentPattern = "ttyACM*"

    # extract the complete port name to establish the connection
    filename = next(currentDirectory.glob(currentPattern), None)

    # in an infinite loop, call the weather function to extract and send information every 30 minutes
    while True:
        fweather(str(filename))
        time.sleep(1800)

main()

C Code from Arduino

/*  
 *   Project Serial Weather
 *   Participants: Christina Lyu & Michelle Tsai Gomez
 *   Arduino code that receives the strings containing the pattern of "celtemp + fahtemp + "|" + risetime + settime + status" in which the status is always in lower case
 *   The file breaks the received string apart and print each respective section based on the information provided. 
 *   For each string the Raspberry sends, the Arduino only receives it once and will keep checking until it receives a new string.
 *   Characters the LED can display include negative sign, space, letter "F" and "C", digits from 0 to 9.
 *   Status that could be displayed using emojis by the LEDs includes cloudy, sunny, rainy, foggy, windy, clear and snowy.
*/


#include <LedControl.h>   //LedControl library: https://www.electronoobs.com/ledcontrol.php
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>


// set the number of LED boards connected to the device to be six
const int numDevices = 6;      // number of MAX7219s used in this case 2
unsigned long bufferLong [14] = {0};  
String readString = "";
String prevString = "";
LedControl lc=LedControl(12,11,10,numDevices);//DATA | CLK | CS/LOAD | number of matrices
const unsigned char scrollText[] PROGMEM ={" 1  "};
// define the LED pattern on how characters will be printed on the boards and how the LEDs will be arranged to simulate the characters
byte F[4] = {B11111111, B00001001, B00001001, B00000001};
byte C[4] = {B01111110, B10000001, B10000001, B10000001};
byte d1[4] = {B10000100, B10000010, B11111111, B10000000};
byte d2[4] = {
  B01110001, 
  B10001001, 
  B10001001, 
  B10000110};
byte d3[4] = {
  B10000001, 
  B10001001, 
  B10001001, 
  B01110110};
byte d4[4] = {B00001111, B00001000, B00001000, B11111111};
byte d5[4] = {
  B10001110, 
  B10001001, 
  B10001001, 
  B01110001};
byte d6[4] = {
  B01111110, 
  B10001001, 
  B10001001, 
  B01110001};
byte d7[4] = {B00000011, B00000001, B00000001, B11111111};
byte d8[4] = {
  B01110110, 
  B10001001, 
  B10001001, 
  B01110110};
byte d9[4] = {
  B10000110, 
  B10001001, 
  B10001001, 
  B01111110};
byte d0[4] = {B01111110, B10000001, B10000001, B01111110};
byte neg[4] = {B00010000, B00010000, B00010000, B00000000};
byte umb[8] = {
    B00001000,  
    B00001100,
    B11001010,
    B10001001,
    B11111001,
    B00001010,
    B00001100,
    B00001000,
};

byte cld[8] = {
    B00111000,  
    B01000100,
    B01000110,
    B00100001,
    B01000101,
    B01000010,
    B01001100,
    B00111000,
};

byte dash[4] = {
    B00100000,  
    B00100000,
    B00100000,
    B00000000,
};

byte space[4] = {B00000000, B00000000, B00000000, B00000000};
byte snw[8] = {
  B10100101,
  B01100110,
  B11100111,
  B00011000,
  B00011000,
  B11100111,
  B01100110,
  B10100101,
};
byte moon[8] = {
  B00111100,
  B01000010,
  B10000001,
  B10000001,
  B10000001,
  B01000010,
  B00100100,
};
byte sun[8] = {
  B10010001,
  B01010010,
  B00011111,
  B11111100,
  B00011000,
  B01001010,
  B10001001,
};
byte wnd[8] = {
  B00000010,
  B00110101,
  B10101001,
  B11000101,
  B00100101,
  B00100101,
  B00100101,
  B00100100,
};
byte fog[8] = {
  B01001001,
  B10010010,
  B01001001,
  B00100100,
  B01001001,
  B10010010,
  B01001001,
  B00100100,
};
int num = 0;

void setup()
{
  // begin serial connection
  Serial.begin(9600);
  // for each LED board
  for (int x=0; x<numDevices; x++)
  {
    lc.shutdown(x,false);       //The MAX72XX is in power-saving mode on startup
    lc.setIntensity(x,2);       // Set the brightness to default value
    lc.clearDisplay(x);         // and clear the display
  }
}

// print the appropriate temperature
void printTemp(String readString) {
  int indBoard = 0;
  int num2 = 0;
  // check each character in the string read from the pi and write the first five LED boards with the appropriate 
  for (int k = 0; k < readString.length(); k ++) {
    char ele = readString[k];
    if (ele == ' ') {
      lc.setRow(indBoard,num2 + 0,space[0]);
      lc.setRow(indBoard,num2 + 1,space[1]);
      lc.setRow(indBoard,num2 + 2,space[2]);
      lc.setRow(indBoard,num2 + 3,space[3]);
    }
    else if (ele == 'C') {
      lc.setRow(indBoard,num2 + 0,C[0]);
      lc.setRow(indBoard,num2 + 1,C[1]);
      lc.setRow(indBoard,num2 + 2,C[2]);
      lc.setRow(indBoard,num2 + 3,C[3]);
    }
    else if (ele == 'F') {
      lc.setRow(indBoard,num2 + 0,F[0]);
      lc.setRow(indBoard,num2 + 1,F[1]);
      lc.setRow(indBoard,num2 + 2,F[2]);
      lc.setRow(indBoard,num2 + 3,F[3]);
      break;
    }
    else if (ele == '1') {
      lc.setRow(indBoard,num2 + 0,d1[0]);
      lc.setRow(indBoard,num2 + 1,d1[1]);
      lc.setRow(indBoard,num2 + 2,d1[2]);
      lc.setRow(indBoard,num2 + 3,d1[3]);
    }
    else if (ele == '2') {
      lc.setRow(indBoard,num2 + 0,d2[0]);
      lc.setRow(indBoard,num2 + 1,d2[1]);
      lc.setRow(indBoard,num2 + 2,d2[2]);
      lc.setRow(indBoard,num2 + 3,d2[3]);
    }
    else if (ele == '3') {
      lc.setRow(indBoard,num2 + 0,d3[0]);
      lc.setRow(indBoard,num2 + 1,d3[1]);
      lc.setRow(indBoard,num2 + 2,d3[2]);
      lc.setRow(indBoard,num2 + 3,d3[3]);
    }
    else if (ele == '4') {
      lc.setRow(indBoard,num2 + 0,d4[0]);
      lc.setRow(indBoard,num2 + 1,d4[1]);
      lc.setRow(indBoard,num2 + 2,d4[2]);
      lc.setRow(indBoard,num2 + 3,d4[3]);
    }
    else if (ele == '5') {
      lc.setRow(indBoard,num2 + 0,d5[0]);
      lc.setRow(indBoard,num2 + 1,d5[1]);
      lc.setRow(indBoard,num2 + 2,d5[2]);
      lc.setRow(indBoard,num2 + 3,d5[3]);
    }
    else if (ele == '6') {
      lc.setRow(indBoard,num2 + 0,d6[0]);
      lc.setRow(indBoard,num2 + 1,d6[1]);
      lc.setRow(indBoard,num2 + 2,d6[2]);
      lc.setRow(indBoard,num2 + 3,d6[3]);
    }
    else if (ele == '7') {
      lc.setRow(indBoard,num2 + 0,d7[0]);
      lc.setRow(indBoard,num2 + 1,d7[1]);
      lc.setRow(indBoard,num2 + 2,d7[2]);
      lc.setRow(indBoard,num2 + 3,d7[3]);
    }
    else if (ele == '8') {
      lc.setRow(indBoard,num2 + 0,d8[0]);
      lc.setRow(indBoard,num2 + 1,d8[1]);
      lc.setRow(indBoard,num2 + 2,d8[2]);
      lc.setRow(indBoard,num2 + 3,d8[3]);
    }
    else if (ele == '9') {
      lc.setRow(indBoard,num2 + 0,d9[0]);
      lc.setRow(indBoard,num2 + 1,d9[1]);
      lc.setRow(indBoard,num2 + 2,d9[2]);
      lc.setRow(indBoard,num2 + 3,d9[3]);
    }
    else if (ele == '0') {
      lc.setRow(indBoard,num2 + 0,d0[0]);
      lc.setRow(indBoard,num2 + 1,d0[1]);
      lc.setRow(indBoard,num2 + 2,d0[2]);
      lc.setRow(indBoard,num2 + 3,d0[3]);
    }
    else if (ele == '-') {
      lc.setRow(indBoard,num2 + 0,dash[0]);
      lc.setRow(indBoard,num2 + 1,dash[1]);
      lc.setRow(indBoard,num2 + 2,dash[2]);
      lc.setRow(indBoard,num2 + 3,dash[3]);
    } else if (ele == '|') {
      break;
    }
    num2 = num2 + 4;
    if (num2 == 8) {
      indBoard = indBoard + 1;
      num2 = 0;
    }
  }
}

// print the emojis on the last board
void printEmji( String readString, int hour ) {
  // print the emoji based on the status received from the Raspberry Pi
  int len;
  char str[readString.length()+1];
  for (int i = 0; i < readString.length(); i++){
    str[i] = readString[i];
  }
  const char ch = '|';
  char *ret;
  ret = strrchr(str, ch);
  // check if the current time is between the sun rise and the sun set time to determine which emoji to use for clear
  String stime = "";
  stime = stime + ret[0] + ret[1];
  String uptime = "";
  uptime = uptime + ret[2] + ret[3];
  int settime = atoi(stime.c_str());
  int suntime = atoi(uptime.c_str());

  // print the emoji on the LED board
  if (strstr(ret, "cloud") != NULL) {
    lc.setRow(6, 0, cld[0]);
    lc.setRow(6, 1, cld[1]);
    lc.setRow(6, 2, cld[2]);
    lc.setRow(6, 3, cld[3]);
    lc.setRow(6, 4, cld[4]);
    lc.setRow(6, 5, cld[5]);
    lc.setRow(6, 6, cld[6]);
    lc.setRow(6, 7, cld[7]);
  }
  else if (strstr(str, "cloud") != NULL) {
    lc.setRow(6, 0, cld[0]);
    lc.setRow(6, 1, cld[1]);
    lc.setRow(6, 2, cld[2]);
    lc.setRow(6, 3, cld[3]);
    lc.setRow(6, 4, cld[4]);
    lc.setRow(6, 5, cld[5]);
    lc.setRow(6, 6, cld[6]);
    lc.setRow(6, 7, cld[7]);
  }
  else if (strstr(ret, "wind") != NULL) {
    lc.setRow(6, 0, wnd[0]);
    lc.setRow(6, 1, wnd[1]);
    lc.setRow(6, 2, wnd[2]);
    lc.setRow(6, 3, wnd[3]);
    lc.setRow(6, 4, wnd[4]);
    lc.setRow(6, 5, wnd[5]);
    lc.setRow(6, 6, wnd[6]);
    lc.setRow(6, 7, wnd[7]);
  }
  else if (strstr(ret, "fog") != NULL || strstr(ret, "mist") != NULL) {
    lc.setRow(6, 0, fog[0]);
    lc.setRow(6, 1, fog[1]);
    lc.setRow(6, 2, fog[2]);
    lc.setRow(6, 3, fog[3]);
    lc.setRow(6, 4, fog[4]);
    lc.setRow(6, 5, fog[5]);
    lc.setRow(6, 6, fog[6]);
    lc.setRow(6, 7, fog[7]);
  }
  else if (strstr(ret, "rain") != NULL || strstr(ret, "drizzl") != NULL) {
    lc.setRow(6, 0, umb[0]);
    lc.setRow(6, 1, umb[1]);
    lc.setRow(6, 2, umb[2]);
    lc.setRow(6, 3, umb[3]);
    lc.setRow(6, 4, umb[4]);
    lc.setRow(6, 5, umb[5]);
    lc.setRow(6, 6, umb[6]);
    lc.setRow(6, 7, umb[7]);
  }
  else if (strstr(ret, "snow") != NULL) {
    lc.setRow(6, 0, snw[0]);
    lc.setRow(6, 1, snw[1]);
    lc.setRow(6, 2, snw[2]);
    lc.setRow(6, 3, snw[3]);
    lc.setRow(6, 4, snw[4]);
    lc.setRow(6, 5, snw[5]);
    lc.setRow(6, 6, snw[6]);
    lc.setRow(6, 7, snw[7]);
  }
  else if (strstr(ret, "clear") != NULL) {
    if ( hour >= suntime && hour < settime ){
    lc.setRow(6, 0, sun[0]);
    lc.setRow(6, 1, sun[1]);
    lc.setRow(6, 2, sun[2]);
    lc.setRow(6, 3, sun[3]);
    lc.setRow(6, 4, sun[4]);
    lc.setRow(6, 5, sun[5]);
    lc.setRow(6, 6, sun[6]);
    lc.setRow(6, 7, sun[7]);
    }
    else {
    lc.setRow(6, 0, moon[0]);
    lc.setRow(6, 1, moon[1]);
    lc.setRow(6, 2, moon[2]);
    lc.setRow(6, 3, moon[3]);
    lc.setRow(6, 4, moon[4]);
    lc.setRow(6, 5, moon[5]);
    lc.setRow(6, 6, moon[6]);
    lc.setRow(6, 7, moon[7]);
    }
  }
}
// set all the LEDs on all boards to 0
// clear all displays on boards
void clearBoard() {
  lc.setRow(1,0,space[0]);
  lc.setRow(1,1,space[1]);
  lc.setRow(1,2,space[2]);
  lc.setRow(1,3,space[3]);

  lc.setRow(1,4,space[0]);
  lc.setRow(1,5,space[1]);
  lc.setRow(1,6,space[2]);
  lc.setRow(1,7,space[3]);
  
  lc.setRow(2,0,space[0]);
  lc.setRow(2,1,space[1]);
  lc.setRow(2,2,space[2]);
  lc.setRow(2,3,space[3]);

  lc.setRow(2,4,space[0]);
  lc.setRow(2,5,space[1]);
  lc.setRow(2,6,space[2]);
  lc.setRow(2,7,space[3]);
  
  lc.setRow(3,0,space[0]);
  lc.setRow(3,1,space[1]);
  lc.setRow(3,2,space[2]);
  lc.setRow(3,3,space[3]);

  lc.setRow(3,4,space[0]);
  lc.setRow(3,5,space[1]);
  lc.setRow(3,6,space[2]);
  lc.setRow(3,7,space[3]);
  
  lc.setRow(4,0,space[0]);
  lc.setRow(4,1,space[1]);
  lc.setRow(4,2,space[2]);
  lc.setRow(4,3,space[3]);

  lc.setRow(4,4,space[0]);
  lc.setRow(4,5,space[1]);
  lc.setRow(4,6,space[2]);
  lc.setRow(4,7,space[3]);
  
  lc.setRow(5,0,space[0]);
  lc.setRow(5,1,space[1]);
  lc.setRow(5,2,space[2]);
  lc.setRow(5,3,space[3]);

  lc.setRow(5,4,space[0]);
  lc.setRow(5,5,space[1]);
  lc.setRow(5,6,space[2]);
  lc.setRow(5,7,space[3]);
  
  lc.setRow(6,0,space[0]);
  lc.setRow(6,1,space[1]);
  lc.setRow(6,2,space[2]);
  lc.setRow(6,3,space[3]);

  lc.setRow(6,4,space[0]);
  lc.setRow(6,5,space[1]);
  lc.setRow(6,6,space[2]);
  lc.setRow(6,7,space[3]);
}

void loop(){ 
  // wait until the connection is available
  while (!Serial.available()) {}
  while (Serial.available()) {
    delay(30);
    // if the port is available, read each character and append it to the previously read string
    if (Serial.available() > 0) {
      char c = Serial.read();
      readString += c;
    }
  }
  // if the current string is different from the original string, it means that a new string has been sent and the board should be cleared
  if (strcmp(readString.c_str(), prevString.c_str()) != 0){
    clearBoard();
  }
  
  // copying the contents of the 
  // string to char array
  int num = 0;
  String arr[3];
  char str[readString.length() + 1]; 
  
     
  strcpy(str, readString.c_str()); 
  const char s[2] = "|";
  char *token;
   
  /* get the first token */
  token = strtok(str, s);
   
  /* walk through other tokens */
  while( token != NULL ) {
    arr[num] = token;
    num = num + 1;
    //printf( " %s\n", token );   
    token = strtok(NULL, s);
  }
  // call printTemp to print temperature
  printTemp(readString);
  //get the current time
  time_t rawtime;
  struct tm *info;

  time ( &rawtime );
  info = localtime ( &rawtime );
  int hour = info->tm_hour;
  // print emoji with PrintEmji function
  printEmji(readString, hour);
  // update the string holder
  prevString = readString;
  // reset the current string
  readString = "";

}

Modified /etc/rc.local File in Raspberry Pi

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

sudo python -m pip install pyowm
sudo python -m pip install pathlib
sudo python 270/python/pj.py &
exit 0