GUI display train delay information using python

Overview

Get the delay information of the specified route from "yahoo route information" and display it on the display with GUI. You can see the operation information on your smartphone, but when you are in a hurry to leave the house, it is difficult to check. Therefore, we created a real-time operation information display to be installed at the entrance.

environment

python 3.7.3 Raspberry pi 3B+ BeautifulSoup4 tkinter Display bracket case for Kuman 7 inch Raspberry Pi 7 inch display (7INCH_HDMI_LCD-PK)

Preparation

sudo apt-get install python3-tk

sudo apt-get install python3-pil python3-pil.imagetk


# Main subject
## Get the operation status with yahoo operation information
 Use requests and beautifulsoup4 to scrape the operating status of registered routes.
 I referred to this site for the algorithm.
https://qiita.com/hirohiroto522/items/6ff29be1344be805ecb0

## Get an image of the operation status
 Create a program that changes the icon depending on the operation status. Download the icon image from [ICOOON MONO](https://icooon-mono.com/) or [Icon is being distributed!](Http://icon.touch-slide.jp/).

 Put the downloaded image in the "img" directory. The folder structure is as follows.
train_info/img
-train.png
-warning.png
train_info/train_info_gui.py

## Operation status display on tkinter
 How to operate tkinter
https://python.keicode.com/advanced/tkinter.php
 I think it will be helpful.
## Source code

#### **`train_info_gui.py`**
```py

from tkinter import *
import tkinter.ttk as ttk
import os
import requests
from bs4 import BeautifulSoup

from PIL import Image, ImageTk
from datetime import datetime, timedelta
import time
import textwrap
#The acquired character string is displayed as it is under the icon image
#Create main window
root = Tk()

#Main window size
root.geometry("1024x600")

#Main window title
root.title("info")
url_dict = {
    "Yamanote Line": 'https://transit.yahoo.co.jp/traininfo/detail/21/0/', "center lane": 'https://transit.yahoo.co.jp/traininfo/detail/38/0/',
    "Saikyo Line": 'https://transit.yahoo.co.jp/traininfo/detail/50/0/', "Shonan Shinjuku Line": 'https://transit.yahoo.co.jp/traininfo/detail/25/0/',"Choshi Electric Railway":'https://transit.yahoo.co.jp/traininfo/detail/181/0/'
}
train_list = [
    "center lane", "Yamanote Line", "Saikyo Line", "Shonan Shinjuku Line","Choshi Electric Railway"
]

#MainFrame class


class MainFrame(ttk.Frame):
    #constructor
    def __init__(self, master=None, **kwargs):
        #Call the constructor of the parent class
        super().__init__(master, **kwargs)

        # create_Call widgets
        self.create_widgets()

    #Create widget
    def create_widgets(self):
        #Create a frame
        self.frame = Frame(self, bg="AntiqueWhite2", bd=0, height=200, relief="flat")

        #Place the frame
        self.frame.grid(row=0, column=0, columnspan=8, sticky="news")

        #Absolute path for this script
        self.scr_path = os.path.dirname(os.path.abspath(sys.argv[0]))
        #Display title
        self.wt=Label(self.frame, text="Route operation information", bg="AntiqueWhite2", font=("", 80))
        self.wt.place(width=800, x=100, y=10)

        #Operation information icon pass (dictionary)
        self.icon_dict = {
            "normal": Image.open(self.scr_path + "/img/train.png "), "trouble": Image.open(self.scr_path + "/img/warning.png ")
        }

        #Fit the icon size to the screen size (64x64)
        for key, value in self.icon_dict.items():
            self.icon_dict[key] = self.icon_dict[key].resize(
                (64, 64), Image.ANTIALIAS)
            self.icon_dict[key] = ImageTk.PhotoImage(self.icon_dict[key])

        #Route list
        self.wwl = [
            Label(self, text="center lane",  bg="red", font=("", 30, "bold")),
            Label(self, text="Yamanote Line",  bg="lawn green", font=("", 30, "bold")),
            Label(self, text="Saikyo Line",  bg="green", font=("", 30, "bold")),
            Label(self, text="Shonan Shinjuku Line", bg="orange", font=("", 30, "bold")),
            Label(self, text="Choshi Electric Railway", bg="DarkOrange", font=("", 30, "bold"))

        ]

        #Place routes
        for i in range(len(self.wwl)):
            self.wwl[i].grid(row=1, column=i, sticky="news")

        #Initial placement dictionary of operation icons
        self.wwi = [
            Label(self, image=self.icon_dict["normal"], bg="white"),
            Label(self, image=self.icon_dict["normal"], bg="white"),
            Label(self, image=self.icon_dict["normal"], bg="white"),
            Label(self, image=self.icon_dict["normal"], bg="white"),
            Label(self, image=self.icon_dict["normal"], bg="white")
        ]

        #Place the operation icon
        for i in range(len(self.wwi)):
            self.wwi[i].grid(row=2, column=i, sticky="news")

        #Driving situation
        self.wwt = [
            Label(self, text="0", bg="white", font=("", 20)),
            Label(self, text="0", bg="white", font=("", 20)),
            Label(self, text="0", bg="white", font=("", 20)),
            Label(self, text="0", bg="white", font=("", 20)),
            Label(self, text="0", bg="white", font=("", 20))

        ]

        #Place driving situation
        for i in range(len(self.wwt)):
            self.wwt[i].grid(row=3, column=i, sticky="news")

        #Layout
        self.rowconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)
        self.rowconfigure(2, weight=1)
        self.rowconfigure(3, weight=1)
        self.rowconfigure(4, weight=1)
        for i in range(len(self.wwl)):
            self.columnconfigure(i, weight=1)


#Place the mainframe
app = MainFrame(root)
app.pack(side=TOP, expand=1, fill=BOTH)

#Close main window


def wm_close():
    root.destroy()


#Create close button
btn = Button(root, text=" X ", font=('', 16), relief=FLAT, command=wm_close)

#When the screen is resized


def change_size(event):
    #Button position to the upper right
    btn.place(x=root.winfo_width() - 60, y=14)


#Bind screen resizing
root.bind('<Configure>', change_size)

#Maximize the main window
#root.attributes("-zoom", "1")
root.attributes("-fullscreen", "1")

#Always in the foreground
root.attributes("-topmost", True)


def update_train_info():

    count = 0
    app.wt
    #Get operation information of registered routes
    for item in train_list:
        web_requests = requests.get(url_dict[item])

        #Analyze web pages with BeautifulSoup
        soup = BeautifulSoup(
            web_requests.text, 'html.parser')
            
        # .Find the dd tag of the trouble class with find
        if soup.find('dd', class_='normal'):
            status = "normal"
            trouble_text="Normal operation"
            bg="green yellow"
        else:
            status = "trouble"
            text_list=textwrap.wrap(soup.find('dd',class_='trouble').get_text(), 10)
            trouble_text='\n'.join(text_list)
            bg="red4"
        app.wwl[count].configure(text=item)  #Display of route name
        #Displayed with operation information icon
        app.wwi[count].configure(image=app.icon_dict[status],bg=bg)

        #Display operation information
        app.wwt[count].configure(text="{0}".format(trouble_text),bg="AntiqueWhite2")

        #Update display counter
        count += 1
  root.after(300000, update_train_info)
    return


#First start
update_train_info()

#Register callback function

root.after(300000, update_train_info)

#Main loop
root.mainloop()

Commentary

The train icon is displayed during normal driving, and the hazard mark is displayed and information is displayed when a failure occurs. Regarding the implementation, refer to [Python] raspberry pi table clock with weather forecast added. I was allowed to. It is updated every 5 minutes. The background color is http://www.tcl.tk/man/tcl8.4/TkCmd/colors.htm I adjusted it while applying the colors listed in.

05/10 postscript As you pointed out, it was only executed once after 5 minutes and was not a regular execution. By adding root.after (300000, update_train_info) to the end ofdef update_train_info ()to make it a recursive call, it became a regular execution. Thank you very much.

Finished product

Finally, I attached the stand to show it on the 7-inch display. 20200509_175223 (2).jpg

reference

https://myenigma.hatenablog.com/entry/2017/09/15/150945#%E7%94%BB%E5%83%8F%E3%81%AE%E8%A1%A8%E7%A4%BA%E3%81%A8Widget%E3%81%AE%E3%82%B0%E3%83%AA%E3%83%83%E3%83%89%E9%85%8D%E7%BD%AE https://qiita.com/nnahito/items/ad1428a30738b3d93762#%E5%9F%BA%E7%A4%8E https://qiita.com/StrayDog/items/203640d9dc7c801dad0f

Recommended Posts

GUI display train delay information using python
GUI programming in Python using Appjar
Create a python GUI using tkinter
GUI creation in python using tkinter 2
About building GUI using TKinter of Python
GUI creation in python using tkinter part 1
[Python] Progress display by progress bar using tqdm
Get note information using Evernote SDK for Python 3
Scraping using Python
Display and shoot webcam video with Python Kivy [GUI]
Operate Redmine using Python Redmine
Fibonacci sequence using Python
Data analysis using Python 0
Data cleaning using Python
Using Python #external packages
Age calculation using python
[GUI in Python] PyQt5-Dialog-
Search Twitter using Python
Name identification using python
Notes using Python subprocesses
Try using Tweepy [Python2.7]
[Blender Python] Display images on 3D View using OpenGL (bgl)
Try to display various information useful for debugging with python
I tried to notify the train delay information with LINE Notify
Output product information to csv using Rakuten product search API [Python]