Raspberry Pi - web page as a sign (or kiosk)

TL;DR

This is the stuff that lets you get the Pi up and running - meaning displaying a web page. It won't solve all your problems.

Raspberry Pi - web page as a sign (or kiosk)

Raspberry Pis are about the size of a deck of cards and extremely easy to work with. If all you need is to display a web page, they're great.

Setup steps for Pi

Setup WiFi

You're probably going to need an internet connection. This describes how to set up WiFi. If you're using a wired connection, you can skip this.

I apologize for providing a link, but it is the best way to explain what needs to be done. You'll figure it out.

Ref: https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md

Shell

sudo raspi-config

Set the locale and hostname of the Pi

This is important for several reasons:

  • You can use the hostname to identify the Pi to the web page you're displaying
  • The locale affects the keyboard layout. If you don't set it properly, when you press a key, you might not get what you want.
  • You need to set the timezone for the Pi, or it won't know what time it is.

You will need to reboot after this

Install vim

Okay, this isn't strictly necessary and if you prefer to use nano or some other editor, it's fine.

Shell

sudo apt-get install vim

Screensaver

You probably don't want the display to shut off. The easiest way to do this is to use xscreensaver.

Install xscreensaver, so it is easy to shut off the screensaver

Shell

sudo apt-get install xscreensaver

Now shut off the screensaver using the GUI

Make the Pi open a browser in kiosk mode

Set it up to load the browser and display the sign on boot

Add this command as the last line in ~/.profile.

Shell

chromium-browser --kiosk --window-position=0,--window-size=1920,1080 https://www.example.com?kiosk=`hostname`

Set the window size to match your monitor. Set the URL to work with your site.

Test it out a few times on the command line to make sure it does what you want.

Ctrl-Alt-F2 escapes from kiosk mode, default Pi username/password is pi/raspberry. To start the desktop (if you cancel out of kiosk mode, you may need this), use startx

Add a cron job to shut the Pi down

If you're using the Pi to run a sign in the office, there's no point in having the sign display during off hours. Turn it off.

Create a file called: /etc/cron.d/stop

Code

0 19 * * * root /sbin/shutdown -h now > /dev/null 2>&1

Final thoughts

  • Be sure to consider authentication/security. Since these will probably be limited access, you can use the IP address to identify it. Only trusted sources. Or you may argue public access is fine. It's a sign, right? Anyway - be sure to consider whether you are willing to allow access to the web page from sources other than the sign.
  • The Pi doesn't turn on automatically. You need to choose a way to turn the sign on, or never shut it off. It can be a simple switch, a timer, a remote controlled outlet, a smartphone control, or ... http://www.uugear.com/witty-pi-realtime-clock-power-management-for-raspberry-pi/ (which looks like the most fun)
  • You may want to install Teamviewer so you can support it remotely.

This post courtesy of Game Creek Video.

Returning custom headers with FOSRestBundle

The Content-Range header supports a (dgrid) OnDemandGrid

Returning custom headers with FOSRestBundle

PHP

use FOS\RestBundle\View\View as FOSRestView;
...
$view FOSRestView::create();
$view->setData($data);
$view->setHeader'Content-Range''items '.$offset.'-'.($offset+$limit).'/'.$count);
$handler $this->get('fos_rest.view_handler');
return $handler->handle($view);

Ref: https://symfony.com/doc/1.5/bundles/FOSRestBundle/2-the-view-layer.html

Symfony 4

Quick Apache Benchmark test with log in

I have been looking at performance for a web application. I am using ab to compare the response times while adjusting the database indexing.

Shell

# 'log in'
curl -L https://www.example.com/login.php -k -b cookie -c cookie-jar -d username=admin -d password=**** -s > /dev/null
# Run the test -n times (in this case 10)
ab -`grep PHP_session cookie-jar | cut -f6,7 | tr '\t' '='` -n 10 'https://www.example.com/main.php'

What's happening?

The curl command is logging in to the application and saving the cookies in a file named cookie-jar.

The grep command is extracting the session id cookie - name and value - from the cookie-jar and using it to authorize access to a main page for ab.

This post courtesy of Game Creek Video

Generate a .csv from an HTML table on the client side

Have you ever had someone say, "This page is great! Can I get the data and use it in Excel?"

Sometimes, the beautiful data displayed is the result of complex calculations and logic which make adding a .csv or .xlsx export difficult.

As I was looking at the page today, I realized the easiest way to create a .csv might be to extract the data out of the DOM. This had the added advantage of requiring the least amount of development.

The key HTML5 features that can be leveraged for this are Data URIs and the download attribute of the anchor tag.

Data URIs allow you to embed content into a tags. In this example, the data URI is: "data:text/csv;base64,(data here)". This indicates that the data is text, containing CSV and encoded with base64.

The download attribute tells the browser to download the content associated with the link rather than navigating to it.

This code is written in plain JavaScript, no jQuery or other library. It queries the HTML and extracts the values in the table. Multi-column cells are padded to ensure the .csv content aligns to the table. Anything that isn't numeric is enclosed in double-quotes with any embedded double-quotes escaped.

I used two loops - the first to get the data from the DOM and the second to create the .csv. It could probably be done in a single loop as well.

The HTML for the link tag is:

HTML

<a id="export-link" href="" download="nifty.csv">Export to CSV</a>

Code

/* Create a .csv of the table */
                
// Get all the rows
var trs = document.querySelectorAll("tr");
// Declare variables
var i,l,j,k,tds,cs,m,n;
var rows = [];
var cells;
                
// Loop through all the rows
l = trs.length;
for (i = 0; i < l; i++) {
  // Get all the cells on the row
  tds = trs[i].querySelectorAll("th,td");
  k = tds.length;
    if (k > 0) {
      cells = [];
        // Loop through all the cells (including headers)
        for (j = 0; j < k; j++) {
          cells.push(tds[j].textContent);
          // Check if this cell has a colspan
          cs = tds[j].colSpan;
          m = cs - 1;
          // Pad the row to ensure everything lines up
          for (n = 0; n < m; n++) {
            cells.push("");
          }
        }
        // Add the cells as a row
      rows.push(cells);
    }
}
// At this point, rows is a two dimensional array with everything from the table
 
// Create a data-uri of the CSV content
var base64encode, csv = "", values;
 
// Loop through all the rows
l = rows.length;
for (i = 0; i < l; i++) {
   // Loop through all the cells in the row
   k = rows[i].length;
   values = [];
   for(j = 0; j < k; j++) {
     value = rows[i][j];
     // If the value is not a number, enclose it in quotes
     if (isNaN(parseFloat(value,10))) {
       value = '"' + value.replace(/"/,'\\\"') + '"';
     }
     values.push(value);               }
     // Join the cells into a CSV row
     csv += values.join(",") + "\n";
   }
}
// Create the data-uri
base64encode = "data:text/csv;base64," + btoa(csv);
// Update the link
document.getElementById("export-link").href = base64encode;

This post courtesy of Game Creek Video

Symfony 4 - Multiple DataFixtures files

I recently upgraded a Symfony 3.3 application to Symfony 4

Part of the upgrade was loading the DataFixtures.

Symfony 4 recommends you put all your DataFixtures in a single file. I'll get around to that later. However, due to the way I organized the file system for the project, the Doctrine Fixtures Loader could not find the demo data.

Symfony 4 - Multiple DataFixtures files

To resolve the issue, I created a services_dev.yaml file with the following:

Code

services:
    App\DataFixtures\Demo\:
        resource: '../src/DataFixtures/Demo/*'
        tags: [ doctrine.fixture.orm ]

Once I added this file to the development server, the data loaded fine.

Ref: https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html#multiple-files