Wednesday, February 18, 2015

what I'm up to these days

A while back I had been blogging daily about what I do, but had found that I seemed to then gravitate towards tasks that I could accomplish easily and then write about at the end of the day.

Instead, I'm going to occasionally write about some things I'm working on. This will include work-related things as well as tasks and projects related to the Masters in Education that I'm hoping to have completed by April 2016.

One of the bigger work-related projects I'm working on these days is open data. We are working on getting some of our data on Strathcona County's Open Data Portal, as well as taking data that we already release and posting it in a more accessible format. We are also interested in getting teachers and students utilizing open data. As I write this, International Open Data Day is coming up soon.

On a somewhat-related note, we're also looking at Open Badges to highlight professional learning among staff in EIPS.

In terms of ongoing work in EIPS, I wrote up a list the other day of things we are often talking to staff about these days.
And a few things on my to do list at work:
  • publish to do list
  • plan Scratch Day
  • Moodle migration
  • automate creation of Google Apps users from PowerSchool
  • build a Minecraft server image with a web-based (or VNC) control panel
  • help plan summer school technology camps
  • explore web-based project management ideas
And a little Python script I wrote today to translate addresses into latitude and longitude coordinates:

Hopefully next time I'll write about some course-related things that are in progress.

Saturday, February 14, 2015

Datalogging to the Web with Python, Requests, and Phant
I've been looking at various ways of logging data to a web-accessible location, both for students and for my own learning. I think I've come across the simplest and most elegant way of doing this, using (a free data logging service based on their phant engine).

Basically there are three parts to this, setting up the phant storage location, getting the data, and pushing it to the web. Aside from the hardware setup, this all should take about five minutes.

To set up the data storage location, visit and enter the appropriate information. Title and Description are required, and the Fields are the things you will be recording (e.g. humidity and temperature). You can change these later. For more information, check the documentation.

After you click Save, it is very important to make a note of the provided values since this is the only time you will get to see them. Copy them to a document and also use the "Send yourself a copy of your keys" option at the bottom of the page.

So now you have a free, Internet-accessible place to log your data. Of course if you'd like, you can even set up your own phant server.

Step two is developing a way to collect data. This could be something like a barometric pressure sensor connected to an ESP8266 module, a button connected to the GPIO pins of a Raspberry Pi, or data that are already available on the Internet. For this post, we'll use weather data from

Step three is to push the data. I like Python and I've recently discovered the excellent Requests HTTP library. If you're using a Chromebook or you don't want to bother setting up Python 2.7 and installing that library, you can use

Assuming that you have Python 2.7 set up and the Requests library installed, here's some code that will log the current atmospheric pressure.

And there you have it, a few minutes to set up and a few lines of Python to start logging data to the web. Next I'd like to see this all done with a sensor or two connected directly to an ESP8266 module.

Monday, October 27, 2014

A Picture is Worth a Thousand Dollars

Recently one of our schools received an invoice for $1000 for their use of a small copyrighted image on one of their newsletters. After determining that it was in fact a legal invoice, they were forced to pay the royalty for their use of that image.

To avoid this, there are a few ways you can find images (or other media such as songs) that are safe to use for newsletters, websites, etc.

The easiest way to find usable images is the "Usage rights" menu on Google Image Search results. After searching for something, click the Search tools button.

Then click Usage rights and select Labeled for reuse with modification.

This will filter your results to display only images that are likely able to be used. Remember that you still need to provide attribution, unless the image is explicitly tagged as Public Domain. Attribution can be as simple as providing a link to the original source.

For more information, check out the different types of Creative Commons licenses. For songs that you can use in projects check out Jamendo or the YouTube Audio Library.

Thursday, October 9, 2014

Python and Google Apps Provisioning with the Admin SDK Directory API

After wading through documentation, blog posts, and StackOverflow answers I've finally figured out a way to authenticate using OAuth 2.0. Since we didn't want to have to interactively grant "user consent" for each of our domains, this is acting as a "web server" for computer-computer interactions.

I assume that you have Python 2.7 installed (three shalt thou not use), but I'd recommend installing Anaconda to make your life easier for all of this. You'll also need to install the Google APIs Client Library for Python.

EDIT: I was finally able to get it to work with the default SignedJwtAssertionCredentials.
 as well as PyCryptoSignedJWT. To install PyCryptoSignedJWT, download and unzip, then from the command line (in the directory you unziped to) type python install in order to install.

The next step is to set up your project. Here's the documentation from here to "Set up your API":
  • Enable the API access from the Admin console in order to make requests to the Directory API. To enable the API, log in to your admin account and select Security. If you do not see Security listed, select More controls and then Security from the options shown in the gray box. Select API reference, and then select the checkbox to Enable API access. Save your changes.
  • Set up a new project in the Google APIs Console and activate Admin SDK service for this project. See the Google APIs Console Help in the upper right corner of the Console page for more information about creating your API project.

Still in the Developers Console, you'll need to create credentials for your project. Click on Credentials (under APIs) and click the button Create new Client ID and then select Service account.

Download the key file, and make a note of the private key password (which is always "notasecret"). Then click the Okay, got it button.

You'll need to make a note of the Service Account EMAIL ADDRESS that is displayed (a long string of characters ending in and the CLIENT ID (the same string ending with

The next step requires you to authorize your API client to access your admin console. Assuming your're still logged in to your Super Admin account, go to Manage API client access (or go to Security, Advanced Settings, Authentication, Manage third party OAuth Client access). For the Client Name, paste in the CLIENT ID that you noted previously. In the One or More API Scopes, put in a comma-separated list of the scopes that you'll be using. For our example I'd suggest, (you can always change this later). Then click the Authorize button.

The file you downloaded previously will be something like APIProject.p12 but we'll need to convert it to a PEM file. On a Mac or Linux machine this can be done from the command line ( openssl pkcs12 -passin pass:notasecret -in APIProject.p12 -nocerts -out APIProject.pem ), but on Windows other software is required (try Win32OpenSSL that can be downloaded from here). As a last resort for those who don't worry about security, you can convert it using this site.

So you now have a p12 key file, a Service Account Email Address, and of course your Super Admin account. You're set to start writing some code. I like the Spyder development environment that is installed with Anaconda, but feel free to just use Notepad (or Notepad++) if you're so inclined.

Here's the minimum Python code that works for me, fill in the appropriate values for yourself.

superAdmin = ''
serviceAccount = ''
pemFile = 'APIProject.p12'
scope = ''

import httplib2
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials

keyFile = file(p12File, 'rb')
key =
credentials = SignedJwtAssertionCredentials(serviceAccount,

http = httplib2.Http()
httplib2.debuglevel = False #change this to True if you want to see the output
http = credentials.authorize(http=http)
directoryService = build(serviceName='admin', version='directory_v1', http=http)

# You are now authenticated, so you can say something like this:
user = directoryService.users().get(userKey = '')
print user.execute()

Hopefully that's enough to get you started. The documentation about what you can do with the Admin Directory API is here. just remember that some of them will require you to declare other scopes.

Friday, May 2, 2014

Automating Chromebook Enrollment with Arduino/Teensy

If you find yourself enrolling large numbers of Chromebooks on your domain, and you don't have students to help, I've written an Arduino program that can expedite the process.

Because many Arduinos (and Arduino clones such my favorite Teensy) can act as a keyboard, they can be programmed to output keystrokes (and mouse clicks) when a button is pushed. In this case a button is connected to ground and pin 2 on a Teensy that is running the following code (this is also available on GitHub).

Edit: The code on GitHub has been updated to allow two buttons using a Teensy or a Trinket, with the additional button for inputting the Wi-Fi passphrase. I've included a demo video of the new version at the bottom of this post.

String email = "";
String password = "thisisaweakpassword";
const int enrolButton = 2;

#include <Bounce.h>
Bounce button1 = Bounce(enrolButton, 10); // 10 ms debouce

void setup() {
 pinMode(enrolButton, INPUT_PULLUP);

void loop() {
 if(button1.fallingEdge()) {enrol();} // call the enrol function

void enrol() {
 delay(50); // wait for 50 milliseconds before releasing those keys
 delay(2000); // wait for 2 seconds to get the enrol screen
 Keyboard.print(email);; //tab to get to the password field

When you hit the button connected to ground and pin 2, this will send the keystrokes Ctrl-Alt-e and your email and password for enrolling a Chromebook. You'll still manually connect to the Wi-Fi or LAN and click Accept on the licence agreement, but you could probably figure out how to automate that with a few more lines of code here (i.e. using KEY_TAB and KEY_SPACE).

Hopefully this will save you some typing and speed up the Chromebook enrolling process. Let me know if you try this.

Minecraft on a Dell Chromebook

This is what worked on a Dell Chromebook that I tried. It will likely work on other Chromebooks but YMMV.

In order to play Minecraft or use other Java-based programs on a Chromebook, you need to install Linux. However that's not a particularly difficult process thanks to crouton.

Unfortunately it requires the Chromebook to remain in developer mode, meaning you'll need to press Ctrl-d every time you boot it up. As well, is not supported by Google (it may cause hardware, software, or security issues) and may void your warranty.

Make sure you backup/upload any files that are stored locally on your Chromebook before you begin.
  1. Enter recovery mode by holding the esc and refresh keys while you press the power button.
  2. At the recovery screen, press Ctrl-d to reboot into developer mode.
  3. Every time you boot up the Chromebook from now on, you'll need to press Ctrl-d at the "OS verification is OFF" screen. If you "Press SPACE to re-enable" then it will erase the Linux install that we are about to do.
  4. Log in to the Chromebook as usual.
  5. Download crouton from
  6. Press Ctrl-Alt-t to open crosh
  7. Type shell, press enter, and you should be at a chronos@localhost / $ prompt.
  8. To run the crouton install script, type sh -e ~/Downloads/crouton -t unity
  9. It will take a while to run the script and download the files
  10. Answer any questions that the script asks you.
  11. Once that finishes, you can start Linux by typing sudo startunity
You're now running Linux, and you can install software such as Java to run Minecraft.

  1. While still on the Linux side of your Chromebook, press Ctrl-Alt-t to open a terminal window. You should see a prompt that is something like (trusy)username@localhost:~$  where you enter the following commands
  2. sudo apt-add-repository ppa:webupd8team/java
  3. sudo apt-get update
  4. sudo apt-get install oracle-java8-installer
  5. sudo apt-get install oracle-java8-set-default
  6. Make sure you type your password that you entered when setting up Linux, and answer yes to the question about the Java licence.
You can now run Java programs in the Linux install on your Chromebook, which includes Minecraft. If you'd like to use Firefox as a browser on the Linux side, it's as simple as opening a terminal (Ctrl-Alt-t) and typing sudo apt-get install firefox You can also install other Linux games, including the Steam platform.

To start Linux after rebooting the Chromebook (always with Ctrl-d), remember Ctrl-Alt-t then shell then sudo startunity

To switch back and forth between ChromeOS and Linux, press Ctrl-Alt-Shift-Back or Ctrl-Alt-Shift-Forward. Back and forward are the arrow buttons at the top left of your keyboard.

To undo all of this and go back to just a regular Chromebook, reboot and press the spacebar to re-enable OS-verification.

Wednesday, April 9, 2014

Check if Google Apps Users Have Logged in (Google Apps Script)

If you're using Google Apps for Education (with the provisioning API enabled) and have a list of domain users that you want to check if they've logged in or not, here's a quick Spreadsheet script you can try. It queries to see if the user has agreed to the terms or not. Of course you'll need to run this from an account that has admin permissions on your domain.

function onOpen() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{name : "Start Checking", functionName : "startLoop"}];
  spreadsheet.addMenu("Check Users", entries);

function startLoop() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var activeSheet = sheet.getActiveSheet();
  var maxRows = activeSheet.getMaxRows();
  var result = Browser.msgBox('This script will check ' + maxRows + ' rows worth of data from the currently selected cell.', Browser.Buttons.OK_CANCEL);
  if (result != 'cancel') {
    for (var i=0;i<maxRows;i++) {checkUser();}
  } else {Browser.msgBox('Okay, maybe some other time');}

function checkUser() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = SpreadsheetApp.getActiveRange();
  var newRange =  range.offset(0, 1);
  var username = range.getValue();
  var user = UserManager.getUser(username);
  var agreedToTerms = user.getAgreedToTerms();
  var newSelection = range.offset(1, 0);

I'm assuming that you're somewhat familiar with Google Apps Script and using it with Spreadsheets. Let me know in the comments if you need clarification.