In rewriting Auroras.live, I switched to Vue.js. This was done for a few reasons, mostly as a learning exercise, but also because it felt lighter than Angular, plus there’s a lot of code sharing due to the website, the mobile app and parts of the new API’s front end being written in Vue.

One goal I had for the rewrite was to make it easier to manage. I wanted one command to build and deploy the website to match the significantly cleaner code base so I wouldn’t have to SSH into my server and git pull any changes down, and thanks to Vue’s npm run build and GitHub Pages, this can be done.

I changed my scripts section of package.json to look like this:

  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "rm -rf dist && npm run build && cd dist && git init && git add . && git commit -m \"Deploy via script\" && git remote add origin https://github.com/username/myrepo.git && git push --force origin master:gh-pages"
  },

And now when I want to deploy a new version of my site, I can just run npm run deploy from the command line, and within a minute or two I have a new version of the website, ready to go.

I used this for a bit, but then decided I wanted to “timestamp” the build so the end user could see when the site was last updated. I could have done this manually, but that would be an extra step. So instead I set up an export in my vue.config.js file:

process.env.VUE_APP_VERSION = Date().toString()

And then in my App.vue file I added the environment variable:

data() {
    return {
      // ...
      version: process.env.VUE_APP_VERSION,
      // ...
    }
}

And finally I added {{ version }} to the template. Now when I run npm run build, the date the site was built is hard-coded into the site

I plan to write similar scripts for the app, so be sure to check back to see my progress.

I’ve been re-writing my Auroras.live app in Ionic 4, and I decided to give the @ionic/vue beta a try. The documentation is severely lacking, which is understandable, given that it’s beta. I’ve also not used Ionic since whatever version was available in 2016 when I wrote version 1 of my app, so I had to learn a whole bunch of new things.

One thing I had a LOT of difficulty with, was tabs. I could get tabs to show up, but as soon as I clicked on one, the whole page, tab bar and all, would be replaced with whatever tab I had clicked on.

After much hair tearing, I came across a solution in the Ionic Conference demo app. Turns out any tabs needed to be a child of my tabs page.

So this wouldn’t work:

export default new IonicVueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
    {
      path: 'about',
      name: 'about',
      components: About
    }
  ]
});

But this would:

export default new IonicVueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      children: [
        {
          path: 'about',
          name: 'about',
          component: About
        }
      ]
    }
  ]
});

Now, to build the rest!

I’m looking in to BotMan to revamp my existing Messenger-based chatbot and had a lot of trouble getting BotMan to listen. When using BotMan Studio, it’s easy, but I didn’t want to create a whole new Laravel app just to use the software, so I followed BotMan’s integration documentation.

I installed the package, followed the instructions, but nothing was happening. Then after much fiddling, I came across a few things that got it working:

  • The DialogFlow token should be your Client Access Token, which you can find by going into the settings for your DialogFlow agent:
The settings button for DialogFlow
  • You need to add the Laravel Cache to the BotMan Factory:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use BotMan\BotMan\BotMan;
use BotMan\BotMan\BotManFactory;
use BotMan\BotMan\Middleware\DialogFlow;
use BotMan\BotMan\Cache\LaravelCache; // Add this

class AuroraBotController extends Controller
{

  function handleIntent(Request $request) {
    $botman = BotManFactory::create(config('aurorabot.botman', []), new LaravelCache(), app()->make('request')); // And change this line to this
    $dialogflow = DialogFlow::create(config('aurorabot.apikey', null))->listenForAction();
    $botman->middleware->received($dialogflow);

    $botman->hears('get_current_kp', function (BotMan $bot) {
      // Handle the intent here
    })->middleware($dialogflow);

    $botman->listen();

  }
}

Recently I deployed my Laravel app to a droplet on DigitalOcean using the LAMP image. I was scratching my head for a bit because after deployment, I couldn’t get the site to work. I’d just continue to see the default site.

I then realised that I had to disable the default site, as it was conflicting with the new site I’d enabled. So I ran

sudo a2dissite 000-default

And the issue was resolved.

I also found that Laravel would throw errors about not being able to write to logs when attempting to access static resources (e.g. storage/images/test.png or /login) so I needed to:

  • Generate an application key to get the login page to load via php artisan key:generate
  • Assign the new user I had created for the site to the www-data group
  • Run php artisan storage:link
  • chmod the storage folder to 755

Once I had those set up, the site worked as normal. Next step, setting up mod_pagespeed..

I’m working on a Patreon integration for Auroras.live and needed to verify the hash that is sent with the headers by Patreon. I’m using Laravel, but this can easily be tweaked to fit whatever:

<?php
// This example can be copied and pasted into Laravel.
// If you're not using Laravel, change the $request related stuff into PHP's native stuff (e.g. file_get_contents("php:///input") etc.)
function verifyPatreonHash(Request $request) {
$patreonBody = $request->getContent(); // This is the raw **body** of the request, which will be JSON (but don't json_decode it!)
$patreonSignature = $request->header('X-Patreon-Signature'); // And this is the header from Patreon
$webhookSecret = "Patreon Webhook Secret Here"; // This'll be the secret Patreon gave you when you created the webhook
$webhookHash = hash_hmac('md5', $patreonBody, $webhookSecret); // This is the hash we've calculated, based on the body and the secret
if(strtolower($webhookHash) == strtolower($patreonSignature)) {
return true; // Verification succeeded
} else {
return false; // Verification failed
}
}
view raw index.php hosted with ❤ by GitHub

At work, we have a captive portal that non-domain-joined machines must authenticate to at least once a day in order to use the internet. Our firewall lets you set exceptions to that rule, but it’s cumbersome and doesn’t always work.

This poses a problem when setting up a new Raspberry Pi, because Raspbian Jessie Lite doesn’t have lynx installed by default, and you can’t easily use cURL to log in (because of session tokens and such). The solution is to proxy the internet connection from the Pi to the computer and authenticate on the computer

This’ll be a short post, mostly for my own reference later, but I’ll be using PuTTY for this.

  1. Connect to the Pi over SSH. Go into the connection settings for PuTTY. Expand Connection > SSH and click on Tunnels.
  2. For the source port, type 1080. Leave destination blank, but set the radio buttons to “Dynamic” and “Auto”. Click “Add”
  3. Open up Internet Explorer. Go to Tools > Internet Options > Connections > LAN Settings
  4. Tick “Use a Proxy”. Clear out the address and port, and click “Advanced”
  5. Untick “Use the same proxy server for all protocols”
  6. Under the Socks section, set the address to 127.0.0.1 and the port to 1080
  7. In Internet Explorer, try and load a website. Authenticate to the captive portal
  8. Back in PuTTY, connect to your Pi and check that the internet is working by doing something like installing a package, wget-ting a file and so forth.

Success!

I’m writing a Facebook Messenger bot and needed to send the degrees character to the user. The multitude of different ways didn’t work for me (\u00b0 etc.), but here’s a way that did:


// The rest of the messenger code here
$strToSend = "It's 13" . utf8_encode("°") . "C outside";
// And your code to send that message on

A short post, but hopefully it helps someone.

Things have been rather quiet on the photography front, but they’ve been super busy on the programming front. I’ve been writing my own app for the Pebble smart watch. The watch app, which is a miniature front-end for my new aurora hunting website, Auroras.live, is written in Pebble.js using CloudPebble and was tons of fun to create.

You can grab a beta version of the app from the store. It shows you the current weather for your location, tiny coloured gauges for speed, density and Bz, plus current, 1 hour and 4 hour Kp readings, and a three day Kp forecast that also shows up on your timeline.

I’m also working on an Android (and possibly iOS) mobile app, based around the Auroras.live website. It’s not ready to go yet, but I hope to have it done by mid-year, earlier if possible. This’ll be my first official foray into writing a mobile app, so it’s all very exciting.

 

Auroras.live Pebble watch appAuroras.live mobile app (alpha version)

I’m doing a 365 challenge at the moment. A photo a day for a whole year. It’s been fun, except when it comes to Facebook photo management. I didn’t realise until about 100 days in, that Facebook was lumping all of my photos together into one post. People visiting my page would see nothing, except for “David Gray Photography added 100 photos to the album ‘365 Challenge 2015′”. This was very frustrating, because I was working my butt off to post content, but Facebook wasn’t showing it. I resorted to “double-sharing” my post. I’d upload the photo, but tick “Hide from News Feed”, then I’d go to the photo, hit “Share” and share it with my own page. It seemed to work, but I knew there had to be a better solution.

After some more research, I discovered that there is a “Change Date” button in the uploader. By default, Facebook sets the date of the photo to the date you created the album (i.e. January 1st). This might work for photos of a birthday party or a wedding, where it all happens on the one date, but for a steady stream of pictures over the course of a year, it was not good.

Fortunately, Facebook gives you an option to set the dates after upload. To do it with 180 photos would take forever, so I created a bookmarklet which would find and store the month and day (Facebook gives you this info as a tooltip, which is very handy), simulate a click on the “Change Date” link, set the day / month boxes as necessary, simulate a click on the “Save” button, then simulate a click on the “Next” button. This essentially allows me to repeatedly click to set the date for all of my photos. 100 photos in, only 90 to go. Too easy!

If you’d like to use this bookmarket for yourself, drag the link below, up to your Bookmarks toolbar:

Automatically change Facebook photo date

If you’d like the source to inspect and change, check out the JSFiddle. As this was written for myself, the code is going to be messy and all over the place, but I didn’t have time to write neat code.

If you’d like to turn the source into a bookmarklet, or you’d like to write your own, check out this bookmarklet generating site. Put some code in, hit “Convert” and you’ve got a bookmarklet, ready to drag to your toolbar. Just note that Facebook blocks external scripts, so you can’t use jQuery on code destined for Facebook.

Happy renaming!

Last night I printed what has arguably been my first useful thing on my Buccaneer. I came across this lens cap holder a little while ago, but didn’t think to print it until last night. I needed to change the dimensions, so I took the Thing into Thingiverse’s customizer, adjusted the parameters, save it to my account, then printed it.

“Customizer” is a feature on Thingiverse that lets you easily modify certain objects. For example, the lens cap holder let me change the strap width and lens cap diameter without needing to touch any other programs — I simply typed into the text box what my strap’s width was (38mm) and what my lens diameter was (77mm)  and it gave me back a file that I could shove straight into the Buccaneer app and print. There are plenty of other customizable things out there, from music boxes to luggage tags and almost everything else inbetween.

The cap holder was incredibly tough to get on (and off) my strap, as there was literally no wriggle room, so next time I might try 39mm wide instead. As you can see from the image above, I eventually managed to get the holder on, and get my straps back on in the right orientation, but it took a fair amount of struggling and bending to get it on there!