Skip to content

Instantly share code, notes, and snippets.

@ElectricImpSampleCode
Last active April 8, 2016 13:37
Show Gist options
  • Save ElectricImpSampleCode/30eae73113de6fbc0335 to your computer and use it in GitHub Desktop.
Save ElectricImpSampleCode/30eae73113de6fbc0335 to your computer and use it in GitHub Desktop.
Code for the Wireless Weather Station project
// 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);
// 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, 1);
cs.configure(DIGITAL_OUT, 1);
din.configure(DIGITAL_OUT, 0);
// 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 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];
local count = line.len();
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);
@nelson-liu
Copy link

To whom it may concern,
I was working on this project, and was puzzled as to why it was not working: turns out that the forecast.io API processes calls in the format https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE. However, your code (in the agent) calls the API in the format https://api.forecast.io/forecast/APIKEY/LONGITUDE,LATITUDE.

Also on line 187 of the device code, there is a typo. writeD should be write.

Perhaps you could change these?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment