Posts: 15
Joined: Wed Sep 21, 2016 4:35 pm

Starting a service after network up.

Mon May 07, 2018 4:51 am

Hi guys, I've built a headless speed-test unit that should start as soon as things are up and running on the pi. My intention is to use this as a quick way to test for broadband speed.

Im new to the raspberry pi and have search the web for program snippets and information and combined them to create what I've got so far.

Im using a raspberry pi 2B and a 16x2 lcd display with 2 buttons connected to GPIO 16 and 20, 16 being used to shutdown the pi and 20 to rerun the speed-test.

My program (broadband.py) I've copied/modified/create etc. with my new limited knowledge on pi looks like this:

Code: Select all

#!/usr/bin/env python
import Adafruit_CharLCD as LCD
import RPi.GPIO as GPIO
import time
import datetime
import requests
import commands
import subprocess
import speedtest
GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers

# set inputs and pull ups on 16 & 20
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# Define GPIO to LCD mapping
LCD_RS = 14
LCD_E  = 15
LCD_D4 = 18
LCD_D5 = 23
LCD_D6 = 24
LCD_D7 = 25

# Device constants
LCD_WIDTH = 16    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line

# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005

def my_callback(channel):

def main():
  # Main program block

        GPIO.setup(LCD_E, GPIO.OUT)  # E
        GPIO.setup(LCD_RS, GPIO.OUT) # RS
        GPIO.setup(LCD_D4, GPIO.OUT) # DB4
        GPIO.setup(LCD_D5, GPIO.OUT) # DB5
        GPIO.setup(LCD_D6, GPIO.OUT) # DB6
        GPIO.setup(LCD_D7, GPIO.OUT) # DB7

        # Initialise display

        lcd_string("Broadband test",LCD_LINE_1)
        loop_start_time = datetime.datetime(2016,1,3,8,30,20)
        lcd_string(time.strftime("%-d %b  %-I:%M"),LCD_LINE_2)

def lcd_init():
        # Initialise display
        lcd_byte(0x33,LCD_CMD) # 110011 Initialise
        lcd_byte(0x32,LCD_CMD) # 110010 Initialise
        lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
        lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
        lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
        lcd_byte(0x01,LCD_CMD) # 000001 Clear display

def lcd_byte(bits, mode):
        # Send byte to data pins
        # bits = data

        # mode = True  for character
        #        False for command

        GPIO.output(LCD_RS, mode) # RS

        # High bits
        GPIO.output(LCD_D4, False)
        GPIO.output(LCD_D5, False)
        GPIO.output(LCD_D6, False)
        GPIO.output(LCD_D7, False)
        if bits&0x10==0x10:
                GPIO.output(LCD_D4, True)
        if bits&0x20==0x20:
                GPIO.output(LCD_D5, True)
        if bits&0x40==0x40:
                GPIO.output(LCD_D6, True)
        if bits&0x80==0x80:
                GPIO.output(LCD_D7, True)

        # Toggle 'Enable' pin

	# Low bits
        GPIO.output(LCD_D4, False)
        GPIO.output(LCD_D5, False)
        GPIO.output(LCD_D6, False)
        GPIO.output(LCD_D7, False)
        if bits&0x01==0x01:
                GPIO.output(LCD_D4, True)
        if bits&0x02==0x02:
                GPIO.output(LCD_D5, True)
        if bits&0x04==0x04:
                GPIO.output(LCD_D6, True)
        if bits&0x08==0x08:
                GPIO.output(LCD_D7, True)

	# Toggle 'Enable' pin

def lcd_toggle_enable():
        # Toggle enable
        GPIO.output(LCD_E, True)
        GPIO.output(LCD_E, False)

def lcd_string(message,line):
        # Send string to display

        message = message.ljust(LCD_WIDTH," ")

        lcd_byte(line, LCD_CMD)

        for i in range(LCD_WIDTH):

if __name__ == '__main__':
	GPIO.add_event_detect(20, GPIO.FALLING, callback=my_callback, bouncetime=200)
	GPIO.wait_for_edge(16, GPIO.FALLING)
	GPIO.cleanup()       # clean up GPIO on CTRL+C exit
	GPIO.cleanup()           # clean up GPIO on normal exit
	subprocess.call("sudo shutdown -h now", shell=True)

and I call it in a systemd service:

Code: Select all


ExecStart=/usr/bin/python /home/pi/broadband.py

All this works and the service starts but the first screen that comes up displays the wrong time with the code

Code: Select all

 lcd_string("Broadband test",LCD_LINE_1)
        loop_start_time = datetime.datetime(2016,1,3,8,30,20)
        lcd_string(time.strftime("%-d %b  %-I:%M"),LCD_LINE_2)
and if I try to run the test straight away with the push button, poor speed-tests are displayed. If I rerun the test or wait 20 seconds or so before running the test after the first screen appears, the broadband speed I'm expecting shows correctly.


Code: Select all

starts the first display at the latest opportunity but still seams to not be late enough as I still need to give it a few more seconds. And then theres the incorrect time issue unless I rerun the service manually, but that can't be done 'headless'.

I think what I need is a

Code: Select all

condition with a "if ping" or something like that in the .service service area but not sure how to do this.

Any ideas would be appreciate.

Paul Hutch
Posts: 338
Joined: Fri Aug 25, 2017 2:58 pm
Location: Blackstone River Valley, MA, USA
Contact: Website

Re: Starting a service after network up.

Thu May 24, 2018 12:20 am

You'll need to wait until the Pi has received the correct time via NTP. The Pi does not have a real time clock so it uses a fake clock at startup that is only guaranteed to show the startup time as after the last shutdown time, and it increments.

I'm not sure the best way to detect that NTP has updated the time because I haven't built an application where that was important yet. However the current project I'm working on will need to know this so I will be looking in to this more in the coming month.

Return to “Python”