Close

Web-server - Pi - Where to start?

A project log for Not Just Another Coffee Table

Custom coffee table with a DCC train track, automation, LEDs and a web interface

jack-flynnJack Flynn 10/01/2018 at 15:060 Comments

The criteria for the web-server is to not only have full control of the layout and effects but also to provide that control in a clean and friendly manner. There is an epiclly complex package already available for a raspberry pi compatible DCC control called JMRI. Like this project, JMRI is used to interface to off-the-shelf DCC controllers and can work as a standalone interface, web-server or communicate with smartphone apps. My hat goes off to the guys at JMRI as it truly is an excellent bit of software for the hardcore DCC fans. However, for our application I wanted something more friendly for the kids and I was looking for a chance to learn more about the raspberry pi and web development in general. 

Python and Django

So where to begin with the raspberry pi? Well first off I knew I wanted to work in python. Python is an excellent programming language for beginners and is heavily favored in the raspberry pi community. This means there's plenty of support out there and reduces the need to "re-invent the wheel". With that in mind there are plenty of options for getting a pi to display a web page. For this I've used Django;

I'm not claiming to understand Django in it's entirety but for my usage it allows me to run a lightweight web server on the raspberry pi using Python and has a lot of useful features to simplify the process. I followed a useful online tutorial for my first run at Django; Django Girls Tutorial. I then went back to use it as a guideline for my own custom site. 

Database - what's in a name?

The part of Django I found most interesting was the integration of a database. Every train on the DCC controller requires an "address". This is part of how DCC physically communicates with the trains on the physical track. I could have spent my time assigning every variable and detail for each train on my track and stored manually if I wanted to. This would mean that any time we wanted to swap out a train or add an additional train on the layout I would need to reprogram my web server for the new details. Instead, by creating classes in the "models" file I was able to produce a database based on the following details for my trains and lighting. 

class Train(models.Model):
	title = models.CharField(max_length=200)
	description = models.TextField()
	address = models.PositiveSmallIntegerField()
	speed = models.PositiveSmallIntegerField()
	direction = models.BooleanField()
	lightsOn = models.BooleanField(default=True)
	hornIs = models.PositiveSmallIntegerField(default=1)
	silentRunning = models.BooleanField(default=False)
	soundOptions = models.PositiveSmallIntegerField()
	image = models.ImageField()
	created_date = models.DateTimeField(
            default=timezone.now)
	def __str__(self):
		return self.title
		
class Light(models.Model):
	title = models.CharField(max_length=200)
	description = models.TextField()
	address = models.PositiveSmallIntegerField()
	type = models.CharField(max_length=200)
	brightness = models.PositiveSmallIntegerField()
	colour = models.PositiveSmallIntegerField()
	lightsState = models.BooleanField(default=True)
	hexValue = models.CharField(max_length=200)
	created_date = models.DateTimeField(
            default=timezone.now)
	def __str__(self):
		return self.title

By using the database in Django, I can simply go to the "admin" page and fill out a new entry in the page and all of the details will be organised in one place for me, including images which is pretty sweet.

This becomes even more powerful when we go to build the HTML for the site. The website served by Django can have it's HTML generated using the database on the fly with a refresh.  See below;

    {% for train in trains %}

			
			<div class="flex-container">
				<div class="post">
					<h2><a href="">{{ train.title }}</a></h2>
					<p>{{ train.description|linebreaksbr }}</p>

					<ul style="list-style-type:circle">
					<li>Address: {{ train.address }}</li>
					<li>Speed: {{ train.speed }}</li>
					<li>Direction: {{ train.direction }}</li>
					<li>Lights On: {{ train.lightsOn }}</li>
					<li>Horn Loc: {{ train.hornIs }}</li>
					<li>Mute: {{ train.silentRunning }}</li>
					<li>Numb. Sound Options: {{ train.soundOptions }}</li>
					</ul>				
				</div>
				<div>
				<img src="{{ train.image.url }}" alt="No Image">
				</div>
			</div>
		
    {% endfor %}

The beauty of this is by passing the database model "trains" I can generate a display page with the details of each train entry in the database. The "for" loop in the HTML is recognised by Django and it knows to cycle through the database for every train entity and produce the html enclosed in the loop. Then each train in the database has it's related fields, such as it's name -

{{ train.title }}

- pulled and printed out in the html using the Django tags. This produces the following result;

So now I have the power to add, edit and remove trains on the fly as required and the webserver will reactively change the html to display what ever trains are available. The same logic applies with the lighting. It's a really nice feature and one that I may have missed had I not gone through the tutorial.

Discussions