• This repository has been archived on 11/Nov/2022
  • Stars
    star
    389
  • Rank 110,500 (Top 3 %)
  • Language
    Python
  • License
    MIT License
  • Created about 9 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A reverse engineered interface for the BMW i3 Electric Car

BMW i Remote API

A reverse engineered interface for the BMW i3 Electric Car, created initially by Terence Eden, with some code modified by Quentin Stafford-Fraser.

Buy me a coffee

Description

These API calls are designed to allow you to interact with your BMW i3. They were reverse engineered from the official BMW i Remote Android app.

Your use of these API calls is entirely at your own risk. They are neither officially provided nor sanctioned.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Servers

There are three API servers.

  • https://b2vapi.bmwgroup.cn:8592 China
  • https://b2vapi.bmwgroup.us USA
  • https://b2vapi.bmwgroup.com Europe / Rest of World

Authorisation

In order to authenticate against the API you will need to be registered on BMW's Connected Drive service.

You will need:

  1. Your ConnectedDrive registered email address.
  2. Your ConnectedDrive registered password.
  3. The i Remote API Key.
  4. The i Remote API Secret.

You can get the i Remote details from either decompiling the Android App or from intercepting communications between your phone and the BMW server. This is left as an exercise for the reader ☺

Firstly, we use Basic authentication. That means taking the API Key and Secret and Base64 encoding them.

So key:secret becomes a2V5OnNlY3JldA==

We also need to send the following parameters as

  • Content-Type: application/x-www-form-urlencoded
 grant_type=password
&username=whatever%40example.com
&password=p4ssw0rd
&scope=remote_services+vehicle_data

Here's how to do it with curl:

curl \
   -H "Authorization: Basic a2V5OnNlY3JldA==" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=password&username=whatever%40example.com&password=p4ssw0rd&scope=remote_services+vehicle_data" \
   "https://b2vapi.bmwgroup.com/webapi/oauth/token/"

If everything has worked, you should get back the following JSON:

{
  "access_token": "RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R",
  "token_type": "Bearer",
  "expires_in": 28800,
  "refresh_token": "7WgKmEJ2kD1ydl9Hefp01eS8qDGzKnzjeORpA6vtsoFIEanz",
  "scope": "vehicle_data remote_services"
}

You must include

  • Authorization: Bearer RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

in your headers with every request.

The expires_in is in seconds - giving you 8 hours before you have to renew the token.

I've no idea what the refresh_token is for. Once the access_token expires, you can simply re-authenticate and gain a new one.

API

You must include

  • Authorization: Bearer RCQ1hLP4AFaUBW9BjcPUN3i4WgkwF90R

in your headers with every request.

Get Vehicle Data

  • /webapi/v1/user/vehicles/
    • Remember to include the Authorization: Bearer header.

Response

Returns a list of entries, one per registered vehicle.

[
  {
    "remote360": "NOT_SUPPORTED",
    "chargingControl": "WEEKLY_PLANNER",
    "countryCode": "V1-UK",
    "hornBlow": "NOT_SUPPORTED",
    "brand": "BMW_I",
    "smartSolution": "NOT_SUPPORTED",
    "hasAlarmSystem": true,
    "climateControl": "NOT_SUPPORTED",
    "doorUnlock": "ACTIVATED",
    "rangeMap": "RANGE_POLYGON",
    "climateFunction": "AIRCONDITIONING",
    "lscType": "I_LSC_IMM",
    "hub": "HUB_ECE",
    "statisticsAvailable": true,
    "doorLock": "ACTIVATED",
    "intermodalRouting": "AVAILABLE",
    "model": "I3 +REX",
    "vehicleFinder": "ACTIVATED",
    "color": "SOLARORANGE MET. M. AKZE",
    "vin": "WAB1C23456V123456",
    "bodytype": "I01",
    "chargeNow": "NOT_SUPPORTED",
    "supportedChargingModes": [
      "AC_LOW",
      "AC_HIGH",
      "DC"
    ],
    "sendPoi": "ACTIVATED",
    "yearOfConstruction": 2014,
    "climateNow": "ACTIVATED",
    "lightFlash": "ACTIVATED",
    "driveTrain": "BEV_REX",
    "licensePlate": "AB64 1BC",
    "statisticsCommunityEnabled": true,
    "colorCode": "B78",
    "onlineSearchMode": "MAP",
    "dealer": {
      "name": "BMW UK Ltd",
      "country": "GB",
      "postalCode": "GU14 0FB",
      "city": "Farnborough",
      "street": "Summit ONE"
    },
    "lastDestinations": "SUPPORTED"
  }
]

The most important thing here is the VIN - Vehicle Identification Number. You'll need that for all the other API calls as well as the Authorization Bearer.

Get Vehicle Status

  • /webapi/v1/user/vehicles/:VIN/status
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "vehicleStatus": {
        "vin": "WAB1C23456V123456",
        "mileage": 1234,
        "updateReason": "VEHICLE_SHUTDOWN_SECURED",
        "updateTime": "2015-10-30T18:45:04+0100",
        "doorDriverFront": "CLOSED",
        "doorDriverRear": "CLOSED",
        "doorPassengerFront": "CLOSED",
        "doorPassengerRear": "CLOSED",
        "windowDriverFront": "CLOSED",
        "windowDriverRear": "CLOSED",
        "windowPassengerFront": "CLOSED",
        "windowPassengerRear": "CLOSED",
        "trunk": "CLOSED",
        "rearWindow": "INVALID",
        "convertibleRoofState": "INVALID",
        "hood": "CLOSED",
        "doorLockState": "SECURED",
        "parkingLight": "OFF",
        "positionLight": "OFF",
        "remainingFuel": 8.9,
        "remainingRangeElectric": 73,
        "remainingRangeElectricMls": 45,
        "remainingRangeFuel": 126,
        "remainingRangeFuelMls": 78,
        "maxRangeElectric": 134,
        "maxRangeElectricMls": 83,
        "fuelPercent": 99,
        "maxFuel": 9,
        "connectionStatus": "DISCONNECTED",
        "chargingStatus": "INVALID",
        "chargingLevelHv": 58,
        "lastChargingEndReason": "UNKNOWN",
        "lastChargingEndResult": "FAILED",
        "position": {
            "lat": 51.123456,
            "lon": -1.2345678,
            "heading": 211,
            "status": "OK"
        },
        "chargingTimeRemaining": 45,
        "internalDataTimeUTC": "2015-10-30T18:47:44"
    }
}

Values

  • mileage is in Km.
  • remainingFuel is in Litres.
  • maxRangeElectric is in Km.
  • maxRangeElectricMls is in miles.
  • chargingLevelHv is the percentage of charge left in the (High voltage?) battery.
  • maxFuel is in Litres.
  • heading is in degrees.
  • chargingTimeRemaining is in minutes. Please mind that this value is only available if car is actively charging otherwise it is not present in the response.

Valid chargingStatus values appear to be:

  • CHARGING
  • ERROR
  • FINISHED_FULLY_CHARGED
  • FINISHED_NOT_FULL
  • INVALID
  • NOT_CHARGING
  • WAITING_FOR_CHARGING

Valid connectionStatus values appear to be:

  • CHARGING_DONE
  • CHARGING_INTERRUPED [sic]
  • CHARGING_PAUSED
  • CHARGIN_STARTED [sic] TYPO should be CHARGING_STARTED
  • CYCLIC_RECHARGING
  • DISCONNECTED
  • DOOR_STATE_CHANGED
  • NO_CYCLIC_RECHARGING
  • NO_LSC_TRIGGER
  • ON_DEMAND
  • PREDICTION_UPDATE
  • TEMPORARY_POWER_SUPPLY_FAILURE
  • UNKNOWN
  • VEHICLE_MOVING
  • VEHICLE_SECURED
  • VEHICLE_SHUTDOWN
  • VEHICLE_SHUTDOWN_SECURED
  • VEHICLE_UNSECURED

Valid doorLockState values appear to be:

  • UNLOCKED
  • LOCKED (remotely)
  • SECURED (with key fob)

Get Last Trip

Shows the details about your most recent trip.

  • /webapi/v1/user/vehicles/:VIN/statistics/lastTrip
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "lastTrip":{
      "efficiencyValue":0.53,
      "totalDistance":141,
      "electricDistance":100.1,
      "avgElectricConsumption":16.6,
      "avgRecuperation":2,
      "drivingModeValue":0,
      "accelerationValue":0.39,
      "anticipationValue":0.81,
      "totalConsumptionValue":0.79,
      "auxiliaryConsumptionValue":0.66,
      "avgCombinedConsumption":1.9,
      "electricDistanceRatio":71,
      "savedFuel":0,
      "date":"2015-12-01T20:44:00+0100",
      "duration":124
   }
}

Values

Distances appear to be in Kilometres rather than miles, so be sure to adjust accordingly. Multiply by 0.621371 to get miles.

  • totalDistance is in Km.
  • electricDistance is in Km.
  • avgElectricConsumption is in kWh/100Km.
  • avgRecuperation is in kWh/100Km.
  • duration is in minutes.

To convert kWh/100Km to Miles/kWh.

1 / (0.01609344 * avgElectricConsumption)

Get Charging Times

Shows when the car is scheduled to charge.

  • /webapi/v1/user/vehicles/:VIN/chargingprofile
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "weeklyPlanner":{
      "climatizationEnabled":true,
      "chargingMode":"DELAYED_CHARGING",
      "chargingPreferences":"CHARGING_WINDOW",
      "timer1":{
         "departureTime":"07:30",
         "timerEnabled":true,
         "weekdays":[
            "MONDAY"
         ]
      },
      "timer2":{
         "departureTime":"13:00",
         "timerEnabled":false,
         "weekdays":[
            "SATURDAY"
         ]
      },
      "timer3":{
         "departureTime":"08:00",
         "timerEnabled":false,
         "weekdays":[

         ]
      },
      "overrideTimer":{
         "departureTime":"07:30",
         "timerEnabled":false,
         "weekdays":[
            "MONDAY"
         ]
      },
      "preferredChargingWindow":{
         "enabled":true,
         "startTime":"05:02",
         "endTime":"17:31"
      }
   }
}

Values

  • departureTime appears to be the car's local time.

Get Vehicle Destinations

Shows the destinations you've previously sent to the car.

  • /webapi/v1/user/vehicles/:VIN/destinations
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "destinations":[
      {
         "lat":51.53053283691406,
         "lon":-0.08362331241369247,
         "country":"UNITED KINGDOM",
         "city":"LONDON",
         "street":"PITFIELD STREET",
         "type":"DESTINATION",
         "createdAt":"2015-09-25T08:06:11+0200"
      }
   ]
}

Values

  • An array of locations.

Get All Trip Details

Shows the statistics for all trips taken in the vehicle.

  • /webapi/v1/user/vehicles/:VIN/statistics/allTrips
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "allTrips": {
        "avgElectricConsumption": {
            "communityLow": 0,
            "communityAverage": 16.33,
            "communityHigh": 35.53,
            "userAverage": 14.76
        },
        "avgRecuperation": {
            "communityLow": 0,
            "communityAverage": 3.76,
            "communityHigh": 14.03,
            "userAverage": 2.3
        },
        "chargecycleRange": {
            "communityAverage": 121.58,
            "communityHigh": 200,
            "userAverage": 72.62,
            "userHigh": 135,
            "userCurrentChargeCycle": 60
        },
        "totalElectricDistance": {
            "communityLow": 1,
            "communityAverage": 12293.65,
            "communityHigh": 77533.6,
            "userTotal": 3158.66
        },
        "avgCombinedConsumption": {
            "communityLow": 0,
            "communityAverage": 1.21,
            "communityHigh": 6.2,
            "userAverage": 0.36
        },
        "batterySizeMax": 35820,
        "savedCO2": 87.58,
        "savedCO2greenEnergy": 515.177,
        "totalSavedFuel": 0,
        "resetDate": "1970-01-01T01:00:00+0100"
    }
}

Values

  • chargecycleRange is in Km.
  • totalElectricDistance is in Km.
  • savedCO2 is in kg.
  • savedCO2greenEnergy is in kg.
  • batterySizeMaxis in Wh.

I'm not sure what units of the other values are.

Get Range Map

Generate a polyline displaying the predicted range of the vehicle.

  • /webapi/v1/user/vehicles/:VIN/rangemap
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
    "rangemap": {
        "center": {
            "lat": 51.123456,
            "lon": -1.2345678
        },
        "quality": "AVERAGE",
        "rangemaps": [
            {
                "type": "ECO_PRO_PLUS",
                "polyline": [
                    {
                        "lat": 51.6991281509399,
                        "lon": -2.00423240661621
                    },
                    {
                        "lat": 51.6909098625183,
                        "lon": -1.91526889801025
                    },
                    ...
                ]
            },
            {
                "type": "COMFORT",
                "polyline": [
                    {
                        "lat": 51.7212295532227,
                        "lon": -1.7363977432251
                    },
                    {
                        "lat": 51.6991496086121,
                        "lon": -1.73077583312988
                    },
                    ...
                ]
            }
        ]
    }
}

Values

  • ECO_PRO_PLUS driving using the efficient Eco mode.
  • COMFORT driving using comfort mode.

Get misc SoC Data

Get maximum state of charge of your battery and some redundant data.

The URL is different from the other API servers:

  • https://www.bmw-connecteddrive.de/api/vehicle/navigation/v1/VIN
    • Where VIN is your vehicle's VIN.
    • Use the same Authorization: Bearer header as with API Server

Response

example data from a PHEV:
{
  "latitude" : 62.250584,
  "longitude" : 3.7717776,
  "isoCountryCode" : "DEU",
  "auxPowerRegular" : 1.4,
  "auxPowerEcoPro" : 1.2,
  "auxPowerEcoProPlus" : 0.4,
  "soc" : 4.019000053405762,
  "socMax" : 5.6,
  "eco" : "1c94,1206,d9d,d0f,cd3,cf9,e2d,f49,10ec,10ec,117c",
  "norm" : "1e15,12f9,e54,dbf,d82,da7,eed,1017,11d0,1483,19a9",
  "ecoEv" : "c31,799,5c5,5a5,5ae,5fc,6fb,861,9df,9df,9df",
  "normEv" : "cd5,800,613,5f1,5fc,64c,759,8d2,a65,bf8,e7d",
  "vehicleMass" : "1560",
  "kAccReg" : "1440000",
  "kDecReg" : "3420000",
  "kAccEco" : "1548000",
  "kDecEco" : "3240000",
  "kUp" : "1800000",
  "kDown" : "2700000",
  "driveTrain" : "phev_otto",
  "pendingUpdate" : false,
  "vehicleTracking" : true
}

Values

  • socMax current maximum charge. kind of health check of you battery

Sending information to the car

Sending information to the car is slightly complicated.

Your app communicates with the API, the API then communicates with the car's 3G modem, then you have to wait for a response.

If your car is in poor coverage, you can expect significant latency. Often much higher than a typical timeout will allow for.

At a basic level, you can just send a request - for example to lock the doors, or set off-peak charging.

Get Request status

Shows the status of a POSTed request

  • /webapi/v1/user/vehicles/:VIN/serviceExecutionStatus?serviceType=:SERVICE
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Response

{
   "executionStatus":{
      "serviceType":"DOOR_LOCK",
      "status":"EXECUTED",
      "eventId":"[email protected]"
   }
}

Values

Valid statuses are:

  • DELIVERED
  • EXECUTED
  • INITIATED
  • NOT_EXECUTED
  • PENDING
  • TIMED_OUT

The following are valid :SERVICE types, but may not be supported by your vehicle.

POST a command

Instructs the car to perform an action.

  • /webapi/v1/user/vehicles/:VIN/executeService
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.

Available Commands

These commands are all available via the API, but may not be supported by your vehicle.

These are just what I've discovered so far.

Data must be POSTed to the server.

Initiate Charging

If the vehicle is plugged in, but not charging (due to an off peak setting?) it is possible to force the car to charge.

  • serviceType=CHARGE_NOW

Start Climate Control

This will activate climate control within your vehicle.

It appears to be limited to the last temperature you set when you were in the car. I can't find a way to instruct the car to reach a specific temperature.

  • serviceType=CLIMATE_NOW

Lock the doors

Performs central locking.

  • serviceType=DOOR_LOCK

Unlock the doors

This will unlock all the doors on your vehicle.

Please use extreme caution when sending this command. Ensure that you are in sight of the vehicle and are able to lock it if needed.

  • serviceType=DOOR_UNLOCK

If you recievce an error after DOOR_UNLOCK that looks like {"error":{"code":500,"description":"(SmartPhoneUtil-A-2013) Action is forbidden. secretKnowledge is missing but required!"}}

An addition field must be included

  • serviceType=DOOR_UNLOCK
  • bmwSkAnswer=BMW_ACCOUNT_SECURITY_QUESTION_ANSWER

Flash the headlights

If you can't find the vehicle, or need to illuminate something in its vicinity, you can briefly activate the headlights.

  • serviceType=LIGHT_FLASH&count=2
    • I assume that count relates to the number of seconds to keep the light on?

Charging Schedule

Set the peak / off peak charging schedule.

  • serviceType=CHARGING_CONTROL
    • Additional data needs to be sent as parameter data in JSON format. The data itself is the same as returned by Get Charging Times.
# Notes:
# - Linebreaks for "data" have been added for readability only.
curl -i \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencode" \
  --data-urlencode 'serviceType=CHARGING_CONTROL' \
  --data-urlencode 'data={
    "weeklyPlanner":
      {
        "climatizationEnabled": true,
        "chargingMode": "IMMEDIATE_CHARGING",
        "chargingPreferences": "CHARGING_WINDOW",
        "timer1":{
          "departureTime": "12:30",
          "timerEnabled": true,
          "weekdays": []
        },
        "timer2":{
          "weekdays": []
        },
        "timer3":{
          "departureTime": "19:30",
          "timerEnabled": false,
          "weekdays": []
        },
        "overrideTimer": {
          "weekdays": []
        },
        "preferredChargingWindow": {
          "enabled": false,
          "startTime": "00:00",
          "endTime": "00:00"
        }}}' \
  https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/:VIN/executeService
* Instead of `weeklyPlanner` `twoTimesTimer` can be used. 
# Notes:
# - Linebreaks for "data" have been added for readability only.
curl -i \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencode" \
  --data-urlencode 'serviceType=CHARGING_CONTROL' \
  --data-urlencode 'data={
    "twoTimesTimer":
      {
        "climatizationEnabled": true,
        "chargingMode": "DELAYED_CHARGING",
        "chargingPreferences": "CHARGING_WINDOW",
        "timer1":{
          "departureTime": "12:30",
          "timerEnabled": true,
        },
        "timer2":{
          "departureTime": "13:30",
          "timerEnabled": false,
        },
        "preferredChargingWindow": {
          "startTime": "00:00",
          "endTime": "00:00"
        }}}' \
  https://b2vapi.bmwgroup.com/webapi/v1/user/vehicles/:VIN/executeService

Vehicle Finder

  • serviceType=VEHICLE_FINDER
    • I'm not sure what this does.

Response

An example response for all POST commands:

{
    "executionStatus": {
        "serviceType": "LIGHT_FLASH",
        "status": "INITIATED",
        "eventId": "[email protected]"
    }
}

Send POI

Sending a POI to the car.

  • POST /webapi/v1/user/vehicles/:VIN/sendpoi
    • Where :VIN is your vehicle's VIN.
    • Remember to include the Authorization: Bearer header.
    • Remember to include the Content-Type: application/x-www-form-urlencode header.

Body

body={
	"poi": {
		"city": "abc",
		"lat": nn.nnn,
		"lon": nn.nnn,
		"name": "name",
		"rating": -1,
		"postalCode": "12345",
		"street": "Musterstr. 6"
	}
}

Response

HTTP 204

What's Next?

Using these commands you should be able to replicate the functionality of the official app.

If you spot any errors or omissions, please raise an issue or send a Pull Request.

More Repositories

1

SuperTinyIcons

Under 1KB each! Super Tiny Icons are miniscule SVG versions of your favourite website and app logos
HTML
14,675
star
2

BMW-OpenSource

All the Open Source Software provided by BMW for their i3
C
591
star
3

Dynamic-SVG-Calendar-Icon

Here it is, an SVG calendar which always display's today's date.
195
star
4

Sercomm-API

A comprehensive guide to the controlling Sercomm IP Cameras via their inbuit API
178
star
5

Tweet2Embed

Convert a public Tweet into embedded semantic HTML
Python
156
star
6

TweeView

A Tree View For Tweets
JavaScript
94
star
7

Renault-Zoe-API

A basic API for getting information about your Renault Zoe Electric Vehicle.
Python
93
star
8

SVGtestcard

Monitor Calibration Test Cards in SVG - loosely based on the BBC's HD Test Card X
73
star
9

QR-Generator-PHP

QR generator. Supports JPG, GIF, PNG outputs. Image size <=1480px. Error correction. Downloadable images (via content disposition)
PHP
71
star
10

Twitter-Networks

Create a directed network of Twitter followers.
Python
70
star
11

Tate-Hack

A collection of random things for #hackthespace
Python
63
star
12

Extended-Hyperlegible

An updated version of the Atkinson Hyperlegible font from https://brailleinstitute.org/freefont
54
star
13

PythonPals

The Python Pals are "Solve Your Own Adventure" stories to help teach people Python.
43
star
14

RaSMSpberry-Pi

Collection of tools to enable the Raspberry Pi to send SMS via an attached 3G USB dongle
Python
42
star
15

3D-Screenshot-to-3D-Model

Quick script to transform screenshots of 3D movies into a 3D meshes
Python
34
star
16

Open-Source-Shakespeare

A MySQL database of the complete works of William Shakespeare
31
star
17

edent.tel

A semantic contact page built around SVG
HTML
28
star
18

Python-Twitter-Hacks

Being mostly a collection of code snippets to remind me how to do things.
Python
27
star
19

PirateMuseum

A virtual museum of stolen artworks
JavaScript
25
star
20

Amazon-Wishlist-Pricedrop-Alert

Emails you when items on your wishlist drop in price
Python
19
star
21

location-activitypub-symfony

A basic ActivityPub server for sharing your location. Written in PHP / Symfony
JavaScript
19
star
22

Fronius-DataManager-Solar-Logger

Log the performance of your solar panels with Fronius's DataManager
PHP
17
star
23

RGB_Colours

This is the code which powers the Twitter Bot https://twitter.com/RGB_Colours
Python
15
star
24

Shakespeare-Serif-Font

A serif font based on Shakespeare's First Folio.
Python
13
star
25

HyperThread

A way to follow complex conversation threads using a HyperTree
JavaScript
10
star
26

Dabr-For-AppDotNet

A first attempt to get Dabr to use the AppDotNet API
PHP
8
star
27

motion-chart

Create a "Hans Rosling" style motion chart using D3.
6
star
28

aed

A Mobile Web App to find Emergency Defibrillators in South & Central UK
6
star
29

blog-theme

A simple, lightweight, easy to maintain WordPress theme for https://shkspr.mobi/blog/
PHP
5
star
30

South-Up-Aotearoa-Centred-Equal-Earth-Projection-Map

South Up, Aotearoa Centred, Equal-Earth Projection Map
R
4
star
31

WordPress-Calendar-Widget

A simple widget to display a blog's post history as a calendar.
PHP
4
star
32

AvatarPreview

A quick way to preview square and circular avatar images
HTML
3
star
33

Applicationize

A personal collection of Chrome WebApps created using https://applicationize.me/
3
star
34

SuperHub

Virgin Media SuperHub2 and 2ac monitoring scripts.
Python
3
star
35

aframedemo

Demo for GameDevDay.club
HTML
2
star
36

w3c-voice-assistant-cg

Exploration and discussion of standards for voice assistants.
2
star
37

Harry-Potter-Lifx

Control your Lifx bulbs by saying "Lumos" for on, and "Knox" for off. A disgustingly quick and dirty hack. Only works in Chrome.
HTML
2
star
38

Mobile-Web-Torrent

A mobile friendly website for searching for torrents - searching is done by the handset, not the server.
2
star
39

edent

It's me!
1
star
40

WordPress-On-This-Day-Plugin

A plugin to show blog posts published "on this day"
PHP
1
star
41

ThinkingCleaner-WiFi-Roomba-Python

A set of Python tools for interacting with a WiFi Enabled Roomba.
Python
1
star
42

3D-UK-Money

OpenSCAD and STL files to 3D print UK coins. Includes Β£2, Β£1, 50p, 20p, 10p, 5p, 1p.
1
star
43

FloodForecast

Tweeting the Flood Forecast for England and Wales. A BlueLightCamp Hack
Python
1
star
44

AAL

AAL is a Software License which can be added to any Open Source or Closed Source software.
1
star
45

Sudoku-Twitter-Bot-Python

A simple bot for generating Sudoku puzzles and posting them to Twitter.
Python
1
star