Last active
March 18, 2018 21:26
-
-
Save electricimp/376f4d5e019b5e77ab20 to your computer and use it in GitHub Desktop.
Wireless Weather Monitor Project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// WEATHER UPDATE CLASS | |
class WeatherUpdate | |
{ | |
// Simple Squirrel class for interaction with Forecast.io | |
url = "https://api.forecast.io/forecast/" | |
apikey = "YOUR API KEY HERE" | |
function forecastRequest(longitude = 52.205082, latitude = 0.130209) | |
{ | |
// Parameters: longitude and latitude of location for which a forecast is required | |
// Return: configured HTTP request | |
return http.get(url + apikey + "/" + longitude.tostring() + "," + latitude.tostring()) | |
} | |
} | |
// AGENT FUNCTIONS | |
function sendForecast(unusedValue) | |
{ | |
request = weather.forecastRequest(myLongitude, myLatitude) | |
request.sendasync(forecastHandler) | |
} | |
function forecastHandler(response) | |
{ | |
// Decode the JSON-format data from forecast.io (error thrown if invalid) | |
local forecast = http.jsondecode(response.body) | |
if ("hourly" in forecast) | |
{ | |
if ("data" in forecast.hourly) | |
{ | |
// Get second item in array: this is the weather one hour from now | |
local item = forecast.hourly.data[1] | |
// Adjust icon names | |
if (item.icon == "clear-day") item.icon = "clearday" | |
if (item.icon == "clear-night") item.icon = "clearnight" | |
if (item.icon == "partly-cloudy-day") item.icon = "partlycloudyday" | |
if (item.icon == "partly-cloudy-night") item.icon = "partlycloudynight" | |
// Send the icon name to the device | |
device.send("weather.show.forecast", item.icon) | |
} | |
} | |
// Tell the agent get the next forecast in an 15 mins' time | |
if (weatherTimer) imp.cancelwakeup(weatherTimer) | |
weatherTimer = imp.wakeup(900.0, function(){sendForecast(true)}) | |
} | |
// GLOBAL VARIABlES | |
request <- null | |
weather <- WeatherUpdate() | |
weatherTimer <- null | |
myLongitude <- YOUR DATA HERE | |
myLatitude <- YOUR DATA HERE | |
// PROGRAM START | |
// Register the function to call when the device asks for a forecast | |
device.on("weather.get.forecast", sendForecast) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LED MATRIX CLASS | |
class MAX7219 | |
{ | |
MAX7219_REGISTER_BCD = 0x09 | |
MAX7219_REGISTER_BRIGHT = 0x0A | |
MAX7219_REGISTER_SCAN = 0x0B | |
MAX7219_REGISTER_PWR_MODE = 0x0C | |
MAX7219_REGISTER_TEST_MODE = 0x0F | |
// Set the number of characters in your character set | |
alphaCount = 107 | |
charset = [ | |
[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0], // Space - Ascii 32 | |
[0x0,0x10,0x10,0x10,0x10,0x0,0x10,0x0], // ! | |
[0x0,0x24,0x24,0x0,0x0,0x0,0x0,0x0], // ” | |
[0x0,0x24,0x7E,0x24,0x24,0x7E,0x24,0x0], // # | |
[0x0,0x8,0x3E,0x28,0x3E,0xA,0x3E,0x8], // $ | |
[0x0,0x62,0x64,0x8,0x10,0x26,0x46,0x0], // % | |
[0x0,0x10,0x28,0x10,0x2A,0x44,0x3A,0x0], // & | |
[0x0,0x8,0x10,0x0,0x0,0x0,0x0,0x0], // ‘ | |
[0x0,0x4,0x8,0x8,0x8,0x8,0x4,0x0], // ( | |
[0x0,0x20,0x10,0x10,0x10,0x10,0x20,0x0], // ) | |
[0x0,0x0,0x14,0x8,0x3E,0x8,0x14,0x0], // * | |
[0x0,0x0,0x8,0x8,0x3E,0x8,0x8,0x0], // + | |
[0x0,0x0,0x0,0x0,0x0,0x8,0x8,0x10], // , | |
[0x0,0x0,0x0,0x0,0x3E,0x0,0x0,0x0], // - | |
[0x0,0x0,0x0,0x0,0x0,0x18,0x18,0x0], // . | |
[0x0,0x2,0x4,0x8,0x10,0x20,0x40,0x0], // / | |
[0x0,0x3C,0x46,0x4A,0x52,0x62,0x3C,0x0], // 0 - Ascii 48 | |
[0x0,0x30,0x50,0x10,0x10,0x10,0x7C,0x0], // 1 | |
[0x0,0x3C,0x42,0x2,0x3C,0x40,0x7E,0x0], // 2 | |
[0x0,0x3C,0x42,0xC,0x2,0x42,0x3C,0x0], // 3 | |
[0x0,0x8,0x18,0x28,0x48,0x7E,0x8,0x0], // 4 | |
[0x0,0x7E,0x40,0x7C,0x2,0x42,0x3C,0x0], // 5 | |
[0x0,0x3C,0x40,0x7C,0x42,0x42,0x3C,0x0], // 6 | |
[0x0,0x7E,0x2,0x4,0x8,0x10,0x10,0x0], // 7 | |
[0x0,0x3C,0x42,0x3C,0x42,0x42,0x3C,0x0], // 8 | |
[0x0,0x3C,0x42,0x42,0x3E,0x2,0x3C,0x0], // 9 | |
[0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x0], // : - Ascii 58 | |
[0x0,0x0,0x10,0x0,0x0,0x10,0x10,0x20], // | |
[0x0,0x0,0x4,0x8,0x10,0x8,0x4,0x0], // < | |
[0x0,0x0,0x0,0x3E,0x0,0x3E,0x0,0x0], // = | |
[0x0,0x0,0x10,0x8,0x4,0x8,0x10,0x0], // > | |
[0x0,0x3C,0x42,0x4,0x8,0x0,0x8,0x0], // ? | |
[0x0,0x3C,0x4A,0x56,0x5E,0x40,0x3C,0x0], // @ | |
[0x0,0x3C,0x42,0x42,0x7E,0x42,0x42,0x0], // A - Ascii 65 | |
[0x0,0x7C,0x42,0x7C,0x42,0x42,0x7C,0x0], // B | |
[0x0,0x3C,0x42,0x40,0x40,0x42,0x3C,0x0], // C | |
[0x0,0x78,0x44,0x42,0x42,0x44,0x78,0x0], // D | |
[0x0,0x7E,0x40,0x7C,0x40,0x40,0x7E,0x0], // E | |
[0x0,0x7E,0x40,0x7C,0x40,0x40,0x40,0x0], // F | |
[0x0,0x3C,0x42,0x40,0x4E,0x42,0x3C,0x0], // G | |
[0x0,0x42,0x42,0x7E,0x42,0x42,0x42,0x0], // H | |
[0x0,0x7C,0x10,0x10,0x10,0x10,0x7C,0x0], // I | |
[0x0,0x2,0x2,0x2,0x2,0x42,0x3C,0x0], // J | |
[0x0,0x44,0x48,0x70,0x48,0x44,0x42,0x0], // K | |
[0x0,0x40,0x40,0x40,0x40,0x40,0x7E,0x0], // L | |
[0x0,0x42,0x66,0x5A,0x42,0x42,0x42,0x0], // M | |
[0x0,0x42,0x62,0x52,0x4A,0x46,0x42,0x0], // N | |
[0x0,0x3C,0x42,0x42,0x42,0x42,0x3C,0x0], // O | |
[0x0,0x7C,0x42,0x42,0x7C,0x40,0x40,0x0], // P | |
[0x0,0x3C,0x42,0x42,0x52,0x4A,0x3C,0x0], // Q | |
[0x0,0x7C,0x42,0x42,0x7C,0x44,0x42,0x0], // R | |
[0x0,0x3C,0x40,0x3C,0x2,0x42,0x3C,0x0], // S | |
[0x0,0x7C,0x10,0x10,0x10,0x10,0x10,0x0], // T | |
[0x0,0x42,0x42,0x42,0x42,0x42,0x3C,0x0], // U | |
[0x0,0x42,0x42,0x42,0x42,0x24,0x18,0x0], // V | |
[0x0,0x42,0x42,0x42,0x42,0x5A,0x24,0x0], // W | |
[0x0,0x42,0x24,0x18,0x18,0x24,0x42,0x0], // X | |
[0x0,0x44,0x28,0x10,0x10,0x10,0x10,0x0], // Y | |
[0x0,0x7E,0x4,0x8,0x10,0x20,0x7E,0x0], // Z - Ascii 90 | |
[0x0,0xE,0x8,0x8,0x8,0x8,0xE,0x0], // [ | |
[0x0,0x0,0x40,0x20,0x10,0x8,0x4,0x0], // \ | |
[0x0,0x70,0x10,0x10,0x10,0x10,0x70,0x0], // ] | |
[0x0,0x10,0x38,0x54,0x10,0x10,0x10,0x0], // ^ | |
[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF], // _ | |
[0x0,0x1C,0x22,0x78,0x20,0x20,0x7E,0x0], // £ | |
[0x0,0x0,0x38,0x4,0x3C,0x44,0x3C,0x0], // a - Ascii 97 | |
[0x0,0x40,0x40,0x78,0x44,0x44,0x78,0x0], // b | |
[0x0,0x0,0x38,0x40,0x40,0x40,0x38,0x0], // c | |
[0x0,0x4,0x4,0x3C,0x44,0x44,0x3C,0x0], // d | |
[0x0,0x0,0x38,0x44,0x78,0x40,0x3C,0x0], // e | |
[0x0,0x30,0x40,0x60,0x40,0x40,0x40,0x0], // f | |
[0x0,0x3C,0x44,0x44,0x3C,0x4,0x38,0x0], // g | |
[0x0,0x40,0x40,0x40,0x78,0x44,0x44,0x0], // h | |
[0x0,0x20,0x0,0x60,0x20,0x20,0x70,0x0], // i | |
[0x0,0x8,0x0,0x8,0x8,0x48,0x30,0x0], // j | |
[0x0,0x40,0x50,0x60,0x60,0x50,0x48,0x0], // k | |
[0x0,0x40,0x40,0x40,0x40,0x40,0x30,0x0], // l | |
[0x0,0x0,0x68,0x54,0x54,0x54,0x54,0x0], // m | |
[0x0,0x0,0x78,0x44,0x44,0x44,0x44,0x0], // n | |
[0x0,0x0,0x38,0x44,0x44,0x44,0x38,0x0], // o | |
[0x0,0x78,0x44,0x44,0x78,0x40,0x40,0x0], // p | |
[0x0,0x3C,0x44,0x44,0x3C,0x4,0x6,0x0], // q | |
[0x0,0x0,0x1C,0x20,0x20,0x20,0x20,0x0], // r | |
[0x0,0x0,0x38,0x40,0x38,0x4,0x78,0x0], // s | |
[0x0,0x20,0x70,0x20,0x20,0x20,0x18,0x0], // t | |
[0x0,0x0,0x44,0x44,0x44,0x44,0x38,0x0], // u | |
[0x0,0x0,0x44,0x44,0x28,0x28,0x10,0x0], // v | |
[0x0,0x0,0x44,0x54,0x54,0x54,0x28,0x0], // w | |
[0x0,0x0,0x44,0x28,0x10,0x28,0x44,0x0], // x | |
[0x0,0x0,0x44,0x44,0x3C,0x4,0x38,0x0], // y | |
[0x0,0x0,0x7C,0x8,0x10,0x20,0x7C,0x0], // z - Ascii 122 | |
[0x0,0xE,0x8,0x30,0x8,0x8,0xE,0x0], // { | |
[0x0,0x8,0x8,0x8,0x8,0x8,0x8,0x0], // | | |
[0x0,0x70,0x10,0xC,0x10,0x10,0x70,0x0], // } | |
[0x0,0x14,0x28,0x0,0x0,0x0,0x0,0x0], // ~ | |
[0x3C,0x42,0x99,0xA1,0xA1,0x99,0x42,0x3C], // © - Ascii 127 | |
[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], // Block Graphic 1 | |
[0xF,0xF,0xF,0xF,0xFF,0xFF,0xFF,0xFF], | |
[0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF], | |
[0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF], | |
[0xFF,0xFF,0xFF,0xFF,0xF,0xF,0xF,0xF], | |
[0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF], | |
[0xF0,0xF0,0xF0,0xF0,0xF,0xF,0xF,0xF], | |
[0x0,0x0,0x0,0x0,0xF,0xF,0xF,0xF], | |
[0xFF,0xFF,0xFF,0xFF,0x55,0xAA,0x55,0xAA], | |
[0xAA,0x55,0xAA,0x55,0xFF,0xFF,0xFF,0xFF], | |
[0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55], // Block Graphic 11 | |
] | |
// Display Properties | |
clk = null | |
din = null | |
cs = null | |
inverseVideoFlag = false | |
rotateMatrixFlag = false | |
constructor(clockPin, dataPin, selectPin, shouldRotate = false) | |
{ | |
clk = clockPin | |
din = dataPin | |
cs = selectPin | |
// Set these pins as digital outputs | |
clk.configure(DIGITAL_OUT) | |
cs.configure(DIGITAL_OUT) | |
din.configure(DIGITAL_OUT) | |
// Set screen rotation flag | |
rotateMatrixFlag = shouldRotate | |
} | |
function init() | |
{ | |
// Initialise the MAX7219’s parameter registers by writing | |
// the register’s address followed by its 8-bit value | |
// Address and data values from the Maxim Integrated MAX7219 Datasheet: | |
// http://www.maximintegrated.com/datasheet/index.mvp/id/1339 | |
write(MAX7219_REGISTER_BCD, 0x00) // Set MAX7219’s BCD decode mode to ‘none’ | |
write(MAX7219_REGISTER_BRIGHT, 0x01) // Set MAX7219’s LED intensity to a 2/32 duty cycle | |
write(MAX7219_REGISTER_SCAN, 0x07) // Set MAX7219’s scan limit to all eight LED columns | |
write(MAX7219_REGISTER_PWR_MODE, 0x01) // Set MAX7219’s power mode. 0 = power down, 1 = normal | |
write(MAX7219_REGISTER_TEST_MODE, 0x00) // Set MAX7219’s display test mode off | |
} | |
function writeByte(byteValue) | |
{ | |
// Writes a single byte of data to the MAX7219 display controller one bit at a time. | |
// Writes data to the LED in the MAX7219’s 16-bit serial format, which puts the | |
// register address in the first eight bits then the data in the second set of eight bits. | |
for (local i = 8 ; i > 0 ; i--) | |
{ | |
clk.write(0) | |
din.write(byteValue & 0x80) // Extract bit 8 and write it to the LED | |
byteValue = byteValue << 1 // Shift the data bits left by one bit | |
clk.write(1) | |
} | |
} | |
function write(RegisterAddress, value) | |
{ | |
// Writes a single value to the MAX7219, preceded by the register | |
// it is being written to | |
cs.write(0) | |
writeByte(RegisterAddress) | |
writeByte(value) | |
cs.write(1) | |
} | |
function clearDisplay() | |
{ | |
displayLine(" ") | |
} | |
function displayIcon(inputMatrix =[0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF]) | |
{ | |
inputMatrix = rotateMatrix(inputMatrix) | |
for (local k = 0 ; k < 8 ; k++) | |
{ | |
if (inverseVideoFlag) | |
{ | |
writeD(k + 1, ~inputMatrix[k]) | |
} | |
else | |
{ | |
write(k + 1, inputMatrix[k]) | |
} | |
} | |
} | |
function displayChar(asciiValue = 32) | |
{ | |
asciiValue = asciiValue - 32 | |
if (asciiValue < 0 || asciiValue > alphaCount) asciiValue = 0 | |
local inputMatrix = clone(charset[asciiValue]) | |
inputMatrix = rotateMatrix(inputMatrix) | |
for (local k = 0 ; k < 8 ; k++) | |
{ | |
if (inverseVideoFlag == 1) | |
{ | |
write(k + 1, ~inputMatrix[k]) | |
} | |
else | |
{ | |
write(k + 1, inputMatrix[k]) | |
} | |
} | |
} | |
function displayLine(line = "No text entered") | |
{ | |
// Bit-scroll through the characters in the variable ‘line’ | |
local a = 0 | |
local b = 0 | |
local count = 0 | |
local outputMatrix = [0,0,0,0,0,0,0,0] | |
local matrixOne = [0,0,0,0,0,0,0,0] | |
local matrixTwo = [0,0,0,0,0,0,0,0] | |
foreach (index, character in line) | |
{ | |
// Count the number of characters in the line | |
count++ | |
} | |
if (count == 1) | |
{ | |
count = 2 | |
line = " " + line | |
} | |
for (local k = 0 ; k < (count - 1) ; k++) | |
{ | |
// Run through the line character by character up to the penultimate character | |
// Get the current character to be displayed and the next character along by | |
// copying them from the character set array | |
a = line[k] | |
b = line[k + 1] | |
matrixOne = clone(charset[a - 32]) | |
matrixTwo = clone(charset[b - 32]) | |
for (local j = 0 ; j < 8 ; j++) | |
{ | |
// We use two character matrices, one on the left and one on the right. | |
// Line by line, we shift the left matrix's bit pattern one bit at a time. | |
// If the seventh bit of a line in the right-hand matrix is set, | |
// we then set bit 0 of the left-hand matrix. | |
// We then shift the right-hand matrix leftward one bit. | |
outputMatrix = matrixOne | |
outputMatrix = rotateMatrix(outputMatrix) | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
// Write the current character’s matrix | |
if (inverseVideoFlag) | |
{ | |
write(i + 1, ~outputMatrix[i]) | |
} | |
else | |
{ | |
write(i + 1, outputMatrix[i]) | |
} | |
// Use the Logical Shift Left operator to move the line one pixel | |
matrixOne[i] = matrixOne[i] << 1 | |
// Move over second matrix by one pixel | |
if ((matrixTwo[i] & 128) > 0) | |
{ | |
// If bit 7 of the right-hand character’s line is set, | |
// carry it over to bit 0 of the left-hand character | |
matrixOne[i] = matrixOne[i] | (1 << 0) | |
} | |
// Shift right-hand character line left one pixel | |
matrixTwo[i] = (matrixTwo[i] << 1) | |
} | |
imp.sleep(0.04) | |
} | |
} | |
// For the final character, we need to perform a last pixel shift to leave | |
// the character completely on the display | |
outputMatrix = matrixOne | |
outputMatrix = rotateMatrix(outputMatrix) | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
if (inverseVideoFlag) | |
{ | |
write(i + 1, ~outputMatrix[i]) | |
} | |
else | |
{ | |
write(i + 1, outputMatrix[i]) | |
} | |
matrixOne[i] = matrixOne[i] << 1 | |
if ((matrixTwo[i] & 128) > 0) matrixOne[i] = matrixOne[i] | (1 << 0) | |
matrixTwo[i] = (matrixTwo[i] << 1) | |
} | |
imp.sleep(0.04) | |
} | |
function rotateMatrix(inputMatrix) | |
{ | |
// Only rotate the matrix if rotate_matrix_flag has not been set | |
if (rotateMatrixFlag == false) return inputMatrix | |
// Rotate the character matrix through 90 degrees anti-clockwise | |
// Used if the LED matrix pins are connected directly to a breadboard | |
local a = 0 | |
local lineValue = 0 | |
local outputMatrix = [0,0,0,0,0,0,0,0] | |
for (local i = 0 ; i < 8 ; i++) | |
{ | |
lineValue = inputMatrix[i] | |
for (local j = 7 ; j > -1 ; j--) | |
{ | |
a = (lineValue & math.pow(2, j).tointeger()) | |
if (a > 0) outputMatrix[7 - j] = outputMatrix[7 - j] + math.pow(2, i).tointeger() | |
} | |
} | |
return outputMatrix | |
} | |
} | |
// Set up the weather icons | |
iconset <- {} | |
iconset.clearday <- [0x81,0x5A,0x3C,0x7E,0x7E,0x3C,0x5A,0x81] | |
iconset.clearnight <- [0x30,0x18,0xC,0xE,0xE,0xC,0x18,0x30] | |
iconset.rain <- [0x1C,0x7E,0xFF,0xFF,0x7E,0x8,0x52,0x84] | |
iconset.snow <- [0x42,0x24,0x99,0x7E,0x99,0x24,0x42,0x00] | |
iconset.sleet <- [0x1C,0x7E,0xFF,0xFF,0x7E,0x89,0x20,0x85] | |
iconset.wind <- [0x0,0x6,0x1,0xFE,0x0,0xFE,0x1,0x6] | |
iconset.fog <- [0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA] | |
iconset.cloudy <- [0x1C,0x7E,0xFF,0xFF,0x7E,0x0,0x0,0x0] | |
iconset.partlycloudyday <- [0x0,0x1C,0x62,0x81,0x81,0x7E,0x0,0x0] | |
iconset.partlycloudynight <- [0xFF,0xF3,0x9D,0x7E,0x7E,0x81,0xFF,0xFF] | |
// DEVICE FUNCTIONS | |
function displayIcon(iconName) | |
{ | |
// Display the weather by name | |
led.displayLine(iconName) | |
// Sleep for a second | |
imp.sleep(1.0) | |
// Now display the weather icon | |
local icon = clone(iconset.rawget(iconName)) | |
led.displayIcon(icon) | |
} | |
// START OF PROGRAM | |
// Set up the LED Matrix | |
led <- MAX7219(hardware.pin9, hardware.pin7, hardware.pin8, true) | |
led.init() | |
led.clearDisplay() | |
// Set up agent interaction | |
agent.on("weather.show.forecast", displayIcon) | |
// Request a weather forecast from the agent | |
agent.send("weather.get.forecast", true) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment