I Thought He Came With You is Robert Ellison’s blog about software, marketing, politics, photography and time lapse.

How does the Nest Learning Thermostat work?

Nest learning thermostat, learning

Not only does it know when you're home but the Nest Learning Thermostat also knows when you're nearby. Here's how it works.

You crank up the heat to 70 and walk away. Nest then immediately returns to 62 degrees.

Thinking there must be something screwy with the algorithm you turn it back up to 70. Nest knows that it's in trouble so it displays a comforting message like 'Heat set until 10pm', waits for you to leave and then sets the temperature back to 62 degrees.

Giving up on the learning part you use the app to manually program it to keep the heat on. Nest now uses its WiFi connection to phone the gas company and disconnect your service.

Export Google Fit Daily Steps to a Google Sheet

Updated on Thursday, September 13, 2018

Google Fit Daily Step Export

Google Fit is a great way to keep track of your daily step count without needing to carry a Fitbit or other dedicated tracker. It's not easy to get that data out though, as far as I can tell the only way is Google Takeout which is not made for automation. Luckily there is an API and you can do almost anything with Google Sheets.

If you're looking to export your step count this post has everything you need, just follow the instructions below to get your spreadsheet up and running. This is also a good primer on using OAuth2 with Google Apps Script and should be a decent starting point for a more complex Google Fit integration. If you have any questions or feedback please leave a comment below.

To get started you need a Google Sheet, an apps script project attached to the sheet and a Google API Project that will provide access to the Fitness API. That might sound intimidating but it should only take a few minutes to get everything up and running.

In Google Drive create a new spreadsheet and call it whatever you like. Rename the first tab to 'Steps'. Enter 'Date' in cell A1 and 'Steps' in cell B1. To grab history as well create another tab called 'History' with the same headers. Next select 'Script editor...' from the Tools menu which will open a new apps script project.

Give the apps script project a name and then select 'Libraries...' from the Resources menu. Next to 'Add a library' enter 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF ad click Add. This will find the Google OAuth2 library. Choose the most recent version (24 at the time of writing) and click Save. Then select 'Project properties' from the File menu and make a note of the Script ID (a long series of letters and numbers).

Open the Google API Console. Create a new project and name it something like 'Google Fit Sheet'. From the Dashboard click Enable APIs and Services and find and select the Fitness API. Then go to Keys and create an OAuth Client ID. You'll be asked to create a consent screen, the only field you need to enter is the product name (i.e. 'My Fit App'). Then choose Web Application as the application type. You need to set the name and the authorized redirect URL. The redirect URL is https://script.google.com/macros/d/{SCRIPTID}/usercallback replacing {SCRIPTID} with the actual Script ID you made a note of above. After adding this make a note of the Client ID and Client Secret.

Go back to the apps script project and paste the code below into the Code.gs window:

// add your Google API Project OAuth client ID and client secret here
var ClientID = '';
var ClientSecret = '';

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Google Fit')
      .addItem('Authorize if needed (does nothing if already authorized)', 'showSidebar')
      .addItem('Get Steps for Yesterday', 'getSteps')
      .addItem('Get Steps for past 30 days', 'getHistory')
      .addToUi();
}

function getSteps() {
  getStepsForDay(1, 'Steps');
}

function getHistory() {
  for(var day = 1; day <= 30; day++) {
    getStepsForDay(day, 'History');
  }
}

// see step count example at https://developers.google.com/fit/scenarios/read-daily-step-total
function getStepsForDay(daysAgo, tabName) {
  var start = new Date();
  start.setHours(0,0,0,0);
  start.setDate(start.getDate() - daysAgo);

  var end = new Date();
  end.setHours(23,59,59,999);
  end.setDate(end.getDate() - daysAgo);
  
  var fitService = getFitService();
  
  var request = {
    "aggregateBy": [{
      "dataTypeName""com.google.step_count.delta",
      "dataSourceId""derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
    }],
    "bucketByTime": { "durationMillis": 86400000 },
    "startTimeMillis": start.getTime(),
    "endTimeMillis": end.getTime()
  };
  
  var response = UrlFetchApp.fetch('https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate', {
    headers: {
      Authorization: 'Bearer ' + fitService.getAccessToken()
    },
    'method' : 'post',
    'contentType' : 'application/json',
    'payload' : JSON.stringify(request, null, 2)
  });
  
  var json = JSON.parse(response.getContentText());
  var steps = json.bucket[0].dataset[0].point[0].value[0].intVal;
  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(tabName);
  sheet.appendRow([start, steps]);
}

// functions below adapted from Google OAuth example at https://github.com/googlesamples/apps-script-oauth2

function getFitService() {
  // Create a new service with the given name. The name will be used when
  // persisting the authorized token, so ensure it is unique within the
  // scope of the property store.
  return OAuth2.createService('fit')

      // Set the endpoint URLs, which are the same for all Google services.
      .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
      .setTokenUrl('https://accounts.google.com/o/oauth2/token')

      // Set the client ID and secret, from the Google Developers Console.
      .setClientId(ClientID)
      .setClientSecret(ClientSecret)

      // Set the name of the callback function in the script referenced
      // above that should be invoked to complete the OAuth flow.
      .setCallbackFunction('authCallback')

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getUserProperties())

      // Set the scopes to request (space-separated for Google services).
      // see https://developers.google.com/fit/rest/v1/authorization for a list of Google Fit scopes
      .setScope('https://www.googleapis.com/auth/fitness.activity.read')

      // Below are Google-specific OAuth2 parameters.

      // Sets the login hint, which will prevent the account chooser screen
      // from being shown to users logged in with multiple accounts.
      .setParam('login_hint', Session.getActiveUser().getEmail())

      // Requests offline access.
      .setParam('access_type', 'offline')

      // Forces the approval prompt every time. This is useful for testing,
      // but not desirable in a production application.
      //.setParam('approval_prompt', 'force');
}

function showSidebar() {
  var fitService = getFitService();
  if (!fitService.hasAccess()) {
    var authorizationUrl = fitService.getAuthorizationUrl();
    var template = HtmlService.createTemplate(
        '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
        'Close this after you have finished.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    SpreadsheetApp.getUi().showSidebar(page);
  } else {
  // ...
  }
}

function authCallback(request) {
  var fitService = getFitService();
  var isAuthorized = fitService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}

(You can also grab this code at GitHub: google-fit-to-sheets)

Right at the top of the code there are spaces to enter the Client ID and Client Secret from the API Console. Enter these and save the project.

Switch back to your Google Sheet and reload. After reloading there will be a Google Fit menu item. First select Authorize... You'll get a screen to authorize the script and then a sidebar with a link. Click the link to authorize the script to access your Google Fit data. You can then close the sidebar and select Get Steps for Yesterday from the Google Fit menu. You should see a new row added to the spreadsheet with yesterday's date and step count.

The final step is to automate pulling in the data. Go back to the apps script project and select Current project's triggers from the Edit menu. Add a trigger to run getSteps() as a time driven day timer - I recommend between 5 and 6am. You can also click notifications to add an email alert if anything goes wrong, like your Google Fit authorization expiring (in which case you just need to come back and authorize from the Google Fit menu again.

At this point you're all set. Every day the spreadsheet will automatically update with your step count from the day before. You can add charts, moving averages, export to other systems, pull in your weight or BMI, etc. I want to add a seven day moving average step count to this blog somewhere as a semi-public motivational tool... watch this space.

I'm not afraid of Google

A Project Fi display ad on an article about Google's insane targeting prowess

At BGR Chris Smith writes about Google's prodigious data collection:

"But that doesn’t change the fact that Google collects an incredible amount of data about you, especially from that device you use most, your Android phone"

And so I was amused as a Google Fi subscriber on a Pixel XL running Google Chrome and signed into my Google Account that the ad in the middle of the article was for Project Fi. If Google can't help paying BGR under these set of circumstances then we're some way off from the adtech singularity.

The Trust Project, Fake News and a Partial Facebook Uninstall

Updated on Thursday, May 3, 2018

No Facebook app to be found here

The Trust Project is a well meaning but doomed attempt to deal with fake news.

Facebook, Google, Bing and Twitter are all on board because it's important to be seen to be doing something about the problem. Sarah Perez at TechCrunch writes:

"Here’s how this will work in practice: starting today on Facebook, an icon will appear next to articles in the News Feed. When you click on this icon, you can read information the publisher has shared related to their organization’s “ethics and other standards, the journalists’ backgrounds, and how they do their work,” according to an announcement from The Trust Project."

Please take a minute to scroll through the Trust Protocol Phase I MVP. Yes, this is a minimal viable product where your most recent Diversity Staffing Report is required. I don't think they understand what an MVP is. Which would be fine if they understood how to fix the problem. They don't.

Back in January I wrote this about fake news on Facebook:

"The horrible danger is that if you don't fact check every stupid quote on image meme the power of repetition lodges them somewhere in your subconscious where they become that thing that you read somewhere. Which is OK if you only read quality news but deadly if you want to catch up on old friends quickly."

And back in 2010 on cable news and the Fairness Doctrine:

"24-hour news stations are especially bad because most days there just isn’t that much news. This leaves a choice between repeating the news that exists which is boring, or making stuff up which is a lot more fun. Unfortunately It’s also corrosive."

Yes, it would be nice to have a set of standards around more easily vetting the provenance of "news" that you find on the internet. But the problem is with people taking bullshit at face value (myself sometimes included). When you scroll by something that meets the loose standards of your confirmation bias the damage is done. You're not clicking any Trust Project icon and you're sure as fuck not upgrading Acrobat just to read the Breitbart Diversity Staffing Report.

The Trust Project isn't the answer. Facebook just pulled their disputed flag. The Fairness Doctrine isn't coming back. Is there a technology based fix that might work?

"That’s not going to happen, argues Data & Society founder and Microsoft researcher danah boyd. Google, Facebook, Twitter—none of these companies is sitting on a silver-bullet solution. As boyd wrote for us earlier this year, we have more than a technology problem: “[W]e have a cultural problem, one that is shaped by disconnects in values, relationships, and social fabric."

From The Fake News Culprit No One Wants to Identify: You on Backchannel recently. I see. It's up to me. I have to fix it.

I uninstalled Facebook and Twitter from my phone just over a week ago. I'm not abandoning social media entirely (although I toy with this regularly). Just pulling back a bit.

For the first few days I'd regularly find my finger headed to launch Facebook. Every time I had a minute to kill. Facebook has no end (usually) so it works even when my RSS feed is empty. I stocked Feedly up with more wholesome content (Trust Project approved no doubt). By the end of the first week I was sometimes even leaving my phone in my pocket.

Now I catch up on Facebook on my laptop every day or two. It's a much better experience - when you check 200 times a day the feed algorithm gets increasingly desperate to please you. It panics and serves up lame memes from someone who you think must have been a coworker at some point but don't really remember. I get through a few updates from friends that I'm actually interested in and bail before hitting the questionable stuff.

It's up to you too.

Securing the Internet of Things

Updated on Wednesday, February 22, 2017

Securing the Internet of Things

We can’t trust manufactures to build secure connected devices and so routers need to be updated to solve this problem once per network.

The distributed denial of service (DDOS) attack on Friday, October 21 was apparently caused by dodgy webcams. But next time it will be Nest or Alexa or Hue - not picking on Google, Amazon or Philips specifically here, those just happen to be the IOT devices currently plugged into my home network. My washing machine and drier would be as well but fortunately LG’s dismal app has saved me from myself by not working for toffee. Oh, I have some DropCams too. And my car is connected. The next attack will probably just come from me.

My fix: update routers to sandbox these devices. A Nest thermostat can only talk to nest.com. If it wants to DDOS Reddit too bad, no connection allowed no matter how badly the device is compromised.

When a new device is connected the router looks it up (MAC address registry?) and then puts it in the appropriate sandbox.

If Nest needs to connect to weather.gov to check the forecast then Google would need to proxy this via nest.com. If the device goes bad it’s only got one domain to attack (so there’s a pretty good incentive for the manufacturer to make sure it doesn’t).

The only downside is new routers or new router firmware. Given the current state of IOT I’d buy one.

As usual if any of my billionaire investor readers are interested get in touch.

Where did that app icon go, Android?

Where did that app icon go, Android?

As much as I’m looking forward to Daydream VR and trying to train my Google Assistant to swear there is one big problem left with Android that Mountain View should tackle first.

Where the fuck did my icon go Android?

Every so often when I update apps an icon is missing from my home screen. It’s one of sixteen apps that I use frequently enough to have pinned there but I can’t remember what it was until my muscle memory sends my finger flying to the empty square an hour or day later. Until then I’m distracted and can’t focus and scroll helplessly through the recently updated list in Google Play trying to figure out which of the updates is the culprit.

It’s not the first time I’ve been through this so I took a screenshot of my home screen just so I could not go through this again. But Google Photos backed it up and deleted it to save space so it’s somewhere in Drive that I can’t find doing me no good at all. When I figure this out I’m going to borrow my daughter’s instax and keep a hard copy in my wallet.

Google booking me a restaurant and a babysitter at a whim won’t save the time I lose to hunting down missing apps.

It might be fixed in Nougat but I can’t update for an unknown number of months because of device/carrier/manufacturer fragmentation so that’s still Google’s fault.

I have been a HTC loyalist so maybe it’s Sense and not Android in which case sorry Google, I should get mad at HTC instead.

I’m pretty sure it was Goodreads.

Google I/O 2016

An Echo knockoff and rapturous applause for variable font size in a messaging app. Not much innovation so far this year.

The horrific trend in Inbox and now Allo is machine learning auto reply so you can send something canned and inauthentic instead of actually speaking with people. Zombie Robs might approve but I'm far from convinced.

Updated 2016-05-18 14:12:

Android N looks super cool and I can't wait. The #1 productivity enhancement I'd like to see though is copy and paste icons that look like copy and paste. I do not have a clue currently.

Updated 2016-05-18 14:24:

No headset.

Updated 2016-05-18 14:40:

Android Studio is very nice. Eclipse was painful. I actually like Android Studio more than Xamarin which is saying a lot for a C# leaning person.

Automate Google PageSpeed Insights with Apps Script

Upload

Here's a quick script to automatically monitor your Google PageSpeed Insights desktop and mobile scores for a web page:

var pageSpeedApiKey = '...';
var pageSpeedMonitorUrl = '...';

function monitor() {
  var desktop = callPageSpeed('desktop');
  var mobile = callPageSpeed('mobile');
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName('results');
  sheet.appendRow([
                   Utilities.formatDate(new Date(), 'GMT', 'yyyy-MM-dd'),
                   desktop.score,
                   mobile.score
                  ]);
    
    // more available, i.e. desktop.pageStats.numberResources
}

function callPageSpeed(strategy) {
  var pageSpeedUrl = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' + pageSpeedMonitorUrl + '&key=' + pageSpeedApiKey + '&strategy=' + strategy;
  var response = UrlFetchApp.fetch(pageSpeedUrl);
  var json = response.getContentText();
  return JSON.parse(json);
}

You need a spreadsheet with a tab called results and an API key for PageSpeed Insights (activate the API in the console and create an API key for it, the browser based / JavaScript option). Paste the code above into the script editor for the spreadsheet and add your API key and URL to monitor. Then just choose triggers from the Resources menu and schedule the monitor function to run once per day.

Note that this currently just logs the overall score. There are a bunch of other values returned (like number and types of resources on the page) that you could choose to monitor as well. It would also be easy to extend this to monitor more URLs, or to send you an email if the score drops below a threshold.

Google Cloud Vision Sightings

Google Cloud Vision Sightings

I've been feeding webcam images into the Google Cloud Vision API for a few weeks now so I thought I'd take a look at what it thinks it can see. The image above shows every label returned from the API with my confidence going from the bottom to the top and Google's confidence going from left to right (so the top right hand corner contains labels that we both agree on).

Google is super-confident that it has seen a location. Can't really argue with it there.

It's more confident that it has seen an ice hotel than a sunrise (and it has seen a lot of sunrises at this point). Maybe I need to explore the Outer Sunset more.

Google is 60.96% confident that it has seen a ballistic missile submarine. I suppose that's plausible, I do have an ocean view but it's rather far away and unless there was an emergency blow that didn't make the news I'm going to have to call bullshit on that one. It's 72.66% confident that an Aston Martin DB9 went past which is pretty specific. Possibly a helicopter slung delivery?

Maybe I'm sending basically the same image in too many times and the poor system is going quietly mad and throwing out increasingly desperate guesses. Probably I've just learned that I should use 80%+ as my confidence threshold before triggering an email...

(Previously)

Chromecast won't connect to wifi - finally found the fix

Updated on Wednesday, February 22, 2017

Chromecast won't connect to wifi - finally found the fix

I've struggled for a while with Chromecast. The idea is great. I love using my phone rather than a remote. I like the idea of being able to cast any screen or browser tab in principle (in practice I think I've only done this once). I like the nice curated background pictures and that I could get round to using my own photos one day.

But here is how it works in practice. Fire up app. Select Chromecast icon and watch it go through the motions of connecting. Nothing streams. Reboot Chromecast, phone and router. Hard reset Chromecast and configure from scratch again. Reboot everything some more. Disconnect house from grid for ten minutes and switch off gas mains as well to be on the safe side. Finally, streaming! Repeat.

It's miserable. With both a Chromecast and a Chromecast 2 (which I really hoped might fix the problem). I've been through two different routers and I've tried a bunch of different settings but nothing seems to make the thing work. I even renamed the device to remove spaces.

For a while I considered buying an OnHub. Maybe Google's router would work with Chromecast? But it can't be bothered with Ethernet ports for some reason and so I'd need a new switch and then I'd probably need another power port and how important is John Oliver right now anyway (very)?

As much as I want Chromecast to work I've binned the wretched thing and bought an Amazon Fire TV Stick. Same basic principle but with apps on the device rather than your phone and a remote control.

I'd rather not have another remote, but it works instantly and without risking an aneurysm. It's also available with voice control which lets you both search for programs and trigger Alexa (my typical morning is asking Alexa for a flash briefing and then sobbing quietly when a daughter yells 'Alexa, stop... Alexa, play Gangnam Style').

My only gripe so far is that the voice search doesn't search inside non-Amazon apps (Netflix, HBO, etc).