Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Big cleanup

* Separation into multiple files
* added config file (copy config.h-dist to config.h)
* pause screen bug fix
* reordered LCD pins
* made it easier to support other services instead of just runkeeper
  • Loading branch information...
commit fbe0a369b29beed3e5236fe1bd4703263551e179 1 parent 98814b5
@reefab authored
View
1  .gitignore
@@ -1 +1,2 @@
*.swp
+config.h
View
250 Bike/Bike.ino
@@ -26,39 +26,34 @@
#include <EthernetUdp.h>
#include <Time.h>
#include <HTTPClient.h>
-// MAC address
-static uint8_t mac[6] = {
- 0x90, 0xA2, 0xDA, 0x05, 0x00, 0x43 };
-// For NTP init
-unsigned int localPort = 8888; // local port to listen for UDP packets
-IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server
-const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
-byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
-// A UDP instance to let us send and receive packets over UDP
-EthernetUDP Udp;
+LiquidCrystal lcd(4, 5, 6, 7, 8, 9);
EthernetClient client;
-// initialize the library with the numbers of the interface pins
-LiquidCrystal lcd(7, 6, 5, 4, 9, 8);
+#include "config.h"
+#include "runkeeper.h"
+#include "ntp.h"
+
+
// This needs to be pin 2 to use interrupt 0
-int reedPin = 2;
-int buttonPin = 3;
-unsigned int rotationCount = 0;
-unsigned int updateCount = 0;
-// Distance per 'wheel' turn
-float meterPerTurn = 6.66;
+#define reedPin 2
+#define buttonPin 3
// Number of 'wheel' turns needed to recalculate speed/total distance
-int interval = 5;
+#define interval 5
// Minimal number of millisecond between reed switch changes to prevent bounce
-int reedRes = 50;
+#define reedRes 50
// Timeout in seconds, if the reed switch is not activated during this time, pause everything
-int timeOut = 15;
+#define timeOut 15
+
+// Global Vars
+unsigned int rotationCount = 0;
+unsigned int updateCount = 0;
// Distance in meters
unsigned int totalDistance = 0;
float currentSpeed = 0;
boolean screen = true;
boolean done = false;
+boolean uploaded = false;
unsigned long lastReedPress = millis();
unsigned long lastButtonPress = millis();
unsigned long lastUpdate = millis();
@@ -66,22 +61,12 @@ unsigned long currentTime = millis();
unsigned long startTime = millis();
unsigned long totalTime = 0;
unsigned long time_elasped = 0;
-unsigned long timestamp = 0;
unsigned long effectiveTime = 0;
//unsigned long lastTimeUpdate = 0;
-// For display during init and sending to HealthGraph
+// For display during init and sending via API
String startTimeStr;
-byte serverIp[] = {
- 74,50,63,142};
-char apiServer[] = "api.runkeeper.com";
-char apiUri[] = "/fitnessActivities";
-char accessToken[] = "Bearer XXX";
-String json_start = "{\"type\": \"Cycling\",\"start_time\": \"";
-String json_middle_1 = "\",\"notes\": \"Arduino powered stationary bike\",\"total_distance\": ";
-String json_middle_2 = ",\"duration\": ";
-String json_end = "}";
-boolean lastConnected = false;
+#include "display.h"
void setup() {
pinMode(reedPin, INPUT);
@@ -89,14 +74,19 @@ void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
+ lcd.print("Starting up");
+ lcd.setCursor(0, 1);
+ lcd.print("Getting IP");
+
// Reed switch handling by interrupt
attachInterrupt(0, turnCounter, FALLING);
-
- attachInterrupt(1, changeScreen, FALLING);
+ // Action Button
+ attachInterrupt(1, actionButton, FALLING);
Serial.begin(9600);
// start Ethernet and UDP
if (Ethernet.begin(mac) == 0) {
+ lcd.clear();
lcd.print("Failed to configure");
lcd.setCursor(0, 1);
lcd.print("Ethernet using DHCP");
@@ -104,67 +94,19 @@ void setup() {
}
else {
Udp.begin(localPort);
- timestamp = getTimeStamp();
- setTime(timestamp);
+ setTime(getTimeStamp());
startTimeStr = getTimeString();
displayInitScreen();
}
-
lcd.clear();
}
void loop() {
// Activity finished & api push
- if (done == true && !client.connected()) {
+ if (done == true && !client.connected() && !uploaded) {
delay(1000);
lcd.clear();
- String data = json_start;
- data += startTimeStr;
- data += json_middle_1;
- data += totalDistance;
- data += json_middle_2;
- data += (int) (effectiveTime / 1000);
- data += json_end;
- unsigned int bufSize = data.length() +1;
- char apiData[bufSize];
- data.toCharArray(apiData, bufSize);
-
- HTTPClient client(apiServer, serverIp);
- http_client_parameter apiHeaders[] = {
- {
- "Authorization", accessToken }
- ,
- {
- "Content-Type", "application/vnd.com.runkeeper.NewFitnessActivity+json" }
- ,
- {
- NULL, NULL }
- };
- lcd.print("Uploading result");
- delay(500);
- FILE* result = client.postURI(apiUri, NULL, apiData, apiHeaders);
- int returnCode = client.getLastReturnCode();
- lcd.clear();
- if (result!=NULL) {
- client.closeStream(result); // this is very important -- be sure to close the STREAM
- }
- else {
- lcd.print("failed to connect");
- }
- if (returnCode==201) {
- lcd.print("Data uploaded");
- lcd.setCursor(0, 1);
- lcd.print("Session Created");
- // Hang on success
- for(;;);
- }
- else {
- lcd.print("ERROR: Server returned ");
- lcd.setCursor(0, 1);
- lcd.print(returnCode);
- }
- // Hang if finished
- if (lastConnected) for(;;);
+ uploaded = uploadResult(startTimeStr, totalDistance, effectiveTime);
}
else {
// Activity in progres
@@ -195,19 +137,19 @@ void loop() {
delay(500);
unsigned long exitLoop = millis();
effectiveTime = effectiveTime + (exitLoop - enterLoop);
+
+ } else {
// Automatic activity pause
- }
- else {
// Deactivate the "Change Screen Button"
detachInterrupt(1);
// Activate the finish function instead at button press
+ delay(500);
attachInterrupt(1, finishActivity, FALLING);
displayPauseScreen();
detachInterrupt(1);
- attachInterrupt(1, changeScreen, FALLING);
+ attachInterrupt(1, actionButton, FALLING);
}
}
- lastConnected = client.connected();
}
void turnCounter() {
@@ -218,7 +160,7 @@ void turnCounter() {
lastReedPress = millis();
}
-void changeScreen() {
+void actionButton() {
if (millis() - lastButtonPress > 200)
{
screen = !screen;
@@ -236,131 +178,6 @@ unsigned long getTotalTime() {
return effectiveTime;
}
-void displayCurrentScreen() {
- lcd.print("Speed: ");
- lcd.print(currentSpeed);
- lcd.print("km/h");
- lcd.setCursor(0, 1);
- lcd.print("Distance: ");
- if (totalDistance < 1000) {
- lcd.print(totalDistance);
- lcd.print("m");
- }
- else {
- lcd.print((float) totalDistance / 1000);
- lcd.print("km");
- }
-}
-
-void displayGlobalScreen() {
- // FIXME: minutes display > 60
- lcd.print("Avg: ");
- lcd.print(getAverageSpeed());
- lcd.print("km/h");
- lcd.setCursor(0, 1);
- totalTime = getTotalTime();
- int hours = totalTime / 3600000;
- int minutes = totalTime / 60000;
- long seconds = (totalTime % 60000);
- seconds = (long) seconds / 1000;
- String time = "Time: "
- + String(hours)
- + prettyDigits(minutes)
- + prettyDigits(seconds);
- lcd.print(time);
-}
-
-// send an NTP request to the time server at the given address
-unsigned long sendNTPpacket(IPAddress& address)
-{
- // set all bytes in the buffer to 0
- memset(packetBuffer, 0, NTP_PACKET_SIZE);
- // Initialize values needed to form NTP request
- // (see URL above for details on the packets)
- packetBuffer[0] = 0b11100011; // LI, Version, Mode
- packetBuffer[1] = 0; // Stratum, or type of clock
- packetBuffer[2] = 6; // Polling Interval
- packetBuffer[3] = 0xEC; // Peer Clock Precision
- // 8 bytes of zero for Root Delay & Root Dispersion
- packetBuffer[12] = 49;
- packetBuffer[13] = 0x4E;
- packetBuffer[14] = 49;
- packetBuffer[15] = 52;
-
- // all NTP fields have been given values, now
- // you can send a packet requesting a timestamp:
- Udp.beginPacket(address, 123); //NTP requests are to port 123
- Udp.write(packetBuffer,NTP_PACKET_SIZE);
- Udp.endPacket();
-}
-
-unsigned long getTimeStamp() {
- sendNTPpacket(timeServer); // send an NTP packet to a time server
- // wait to see if a reply is available
- delay(1000);
- if ( Udp.parsePacket() ) {
- // We've received a packet, read the data from it
- Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
- //the timestamp starts at byte 40 of the received packet and is four bytes,
- // or two words, long. First, esxtract the two words:
- unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
- unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
- // combine the four bytes (two words) into a long integer
- // this is NTP time (seconds since Jan 1 1900):
- unsigned long secsSince1900 = highWord << 16 | lowWord;
- // now convert NTP time into Unix timestamp:
- const unsigned long seventyYears = 2208988800UL;
- unsigned long epoch = secsSince1900 - seventyYears;
- return epoch;
- }
-}
-
-String prettyDigits(int digits){
- // utility function for digital clock display: prints preceding colon and leading 0
- String output = ":";
- if(digits < 10)
- output += '0';
- output += digits;
- return output;
-}
-
-String getTimeString() {
- String str_time;
- str_time += String(dayShortStr(weekday())) + ", "
- + String(day()) + " "
- + String(monthShortStr(month())) + " "
- + String(year())
- + " "
- + String(hour())
- + prettyDigits(minute())
- + prettyDigits(second());
- return str_time;
-}
-
-void displayPauseScreen() {
- lcd.clear();
- lcd.print("Activity paused.");
- delay(1000);
- lcd.clear();
- lcd.print("Press button ");
- lcd.setCursor(0, 1);
- lcd.print("to finish");
- delay(1000);
-}
-
-void displayInitScreen() {
- lcd.print("IP: ");
- lcd.print(Ethernet.localIP());
- lcd.setCursor(0, 1);
- for (int i = 0;i < 16;i++) lcd.print(startTimeStr.charAt(i));
- delay(2500);
- lcd.setCursor(0, 1);
- for (int i = 1;i < 32;i++) lcd.print(" ");
- lcd.setCursor(0, 1);
- for (int i = 16;i < startTimeStr.length();i++) lcd.print(startTimeStr.charAt(i));
- delay(2500);
-}
-
void finishActivity() {
lcd.clear();
lcd.print("Activity");
@@ -369,3 +186,4 @@ void finishActivity() {
done = true;
}
+
View
19 Bike/config.h-dist
@@ -0,0 +1,19 @@
+/*
+ * Cycling Pusher Configuration
+ *
+ * Copy this file to "config.h" and edit.
+ *
+ * Created on: 5.03.2012
+ * Author: reefab
+ */
+
+#include <Arduino.h>
+
+// MAC address
+static uint8_t mac[6] = {
+ 0x90, 0xA2, 0xDA, 0x05, 0x00, 0x43 };
+// Distance per 'wheel' turn
+const float meterPerTurn = 6;
+
+// Access Token
+#define accessToken "Bearer XXXXXXXXXX"
View
60 Bike/display.h
@@ -0,0 +1,60 @@
+void displayCurrentScreen() {
+ lcd.print("Speed: ");
+ lcd.print(currentSpeed);
+ lcd.print("km/h");
+ lcd.setCursor(0, 1);
+ lcd.print("Distance: ");
+ if (totalDistance < 1000) {
+ lcd.print(totalDistance);
+ lcd.print("m");
+ }
+ else {
+ lcd.print((float) totalDistance / 1000);
+ lcd.print("km");
+ }
+}
+
+void displayGlobalScreen() {
+ // FIXME: minutes display > 60
+ lcd.print("Avg: ");
+ lcd.print(getAverageSpeed());
+ lcd.print("km/h");
+ lcd.setCursor(0, 1);
+ totalTime = getTotalTime();
+ int hours = totalTime / 3600000;
+ int minutes = totalTime / 60000;
+ long seconds = (totalTime % 60000);
+ seconds = (long) seconds / 1000;
+ String time = "Time: "
+ + String(hours)
+ + prettyDigits(minutes)
+ + prettyDigits(seconds);
+ lcd.print(time);
+}
+
+void displayPauseScreen() {
+ lcd.clear();
+ lcd.print("Activity paused.");
+ delay(1000);
+ lcd.clear();
+ lcd.print("Press button ");
+ lcd.setCursor(0, 1);
+ lcd.print("to finish");
+ delay(1000);
+}
+
+void displayInitScreen() {
+ lcd.clear();
+ lcd.print("IP: ");
+ lcd.print(Ethernet.localIP());
+ lcd.setCursor(0, 1);
+ for (int i = 0;i < 16;i++) lcd.print(startTimeStr.charAt(i));
+ delay(2500);
+ lcd.setCursor(0, 1);
+ for (int i = 1;i < 32;i++) lcd.print(" ");
+ lcd.setCursor(0, 1);
+ for (int i = 16;i < startTimeStr.length();i++) lcd.print(startTimeStr.charAt(i));
+ delay(2500);
+}
+
+
View
77 Bike/ntp.h
@@ -0,0 +1,77 @@
+// NTP
+const unsigned int localPort = 8888; // local port to listen for UDP packets
+const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
+byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
+// For NTP init
+IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server
+// A UDP instance to let us send and receive packets over UDP
+EthernetUDP Udp;
+
+// send an NTP request to the time server at the given address
+unsigned long sendNTPpacket(IPAddress& address)
+{
+ // set all bytes in the buffer to 0
+ memset(packetBuffer, 0, NTP_PACKET_SIZE);
+ // Initialize values needed to form NTP request
+ // (see URL above for details on the packets)
+ packetBuffer[0] = 0b11100011; // LI, Version, Mode
+ packetBuffer[1] = 0; // Stratum, or type of clock
+ packetBuffer[2] = 6; // Polling Interval
+ packetBuffer[3] = 0xEC; // Peer Clock Precision
+ // 8 bytes of zero for Root Delay & Root Dispersion
+ packetBuffer[12] = 49;
+ packetBuffer[13] = 0x4E;
+ packetBuffer[14] = 49;
+ packetBuffer[15] = 52;
+
+ // all NTP fields have been given values, now
+ // you can send a packet requesting a timestamp:
+ Udp.beginPacket(address, 123); //NTP requests are to port 123
+ Udp.write(packetBuffer,NTP_PACKET_SIZE);
+ Udp.endPacket();
+}
+
+unsigned long getTimeStamp() {
+ sendNTPpacket(timeServer); // send an NTP packet to a time server
+ // wait to see if a reply is available
+ delay(1000);
+ if ( Udp.parsePacket() ) {
+ // We've received a packet, read the data from it
+ Udp.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
+ //the timestamp starts at byte 40 of the received packet and is four bytes,
+ // or two words, long. First, esxtract the two words:
+ unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
+ unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
+ // combine the four bytes (two words) into a long integer
+ // this is NTP time (seconds since Jan 1 1900):
+ unsigned long secsSince1900 = highWord << 16 | lowWord;
+ // now convert NTP time into Unix timestamp:
+ const unsigned long seventyYears = 2208988800UL;
+ unsigned long epoch = secsSince1900 - seventyYears;
+ return epoch;
+ }
+}
+
+String prettyDigits(int digits){
+ // utility function for digital clock display: prints preceding colon and leading 0
+ String output = ":";
+ if(digits < 10)
+ output += '0';
+ output += digits;
+ return output;
+}
+
+String getTimeString() {
+ String str_time;
+ str_time += String(dayShortStr(weekday())) + ", "
+ + String(day()) + " "
+ + String(monthShortStr(month())) + " "
+ + String(year())
+ + " "
+ + String(hour())
+ + prettyDigits(minute())
+ + prettyDigits(second());
+ return str_time;
+}
+
+
View
69 Bike/runkeeper.h
@@ -0,0 +1,69 @@
+/*
+ * Cycling Pusher Runkeeper lib
+ *
+ *
+ * Created on: 5.03.2012
+ * Author: reefab
+ */
+
+#include <Arduino.h>
+#include <HTTPClient.h>
+
+byte serverIp[] = {
+ 74,50,63,142};
+#define apiServer "api.runkeeper.com"
+#define apiUri "/fitnessActivities"
+#define json_start "{\"type\": \"Cycling\",\"start_time\": \""
+#define json_middle_1 "\",\"notes\": \"Arduino powered stationary bike\",\"total_distance\": "
+#define json_middle_2 ",\"duration\": "
+#define json_end "}"
+
+HTTPClient http_client(apiServer, serverIp);
+
+boolean uploadResult(String startTimeStr, int totalDistance, int effectiveTime)
+{
+ String data = json_start;
+ data += startTimeStr;
+ data += json_middle_1;
+ data += totalDistance;
+ data += json_middle_2;
+ data += (int) (effectiveTime / 1000);
+ data += json_end;
+ unsigned int bufSize = data.length() +1;
+ char apiData[bufSize];
+ data.toCharArray(apiData, bufSize);
+
+ http_client_parameter apiHeaders[] = {
+ {
+ "Authorization", accessToken }
+ ,
+ {
+ "Content-Type", "application/vnd.com.runkeeper.NewFitnessActivity+json" }
+ ,
+ {
+ NULL, NULL }
+ };
+ lcd.print("Uploading result");
+ delay(500);
+ FILE* result = http_client.postURI(apiUri, NULL, apiData, apiHeaders);
+ int returnCode = http_client.getLastReturnCode();
+ lcd.clear();
+ if (result!=NULL) {
+ http_client.closeStream(result); // this is very important -- be sure to close the STREAM
+ }
+ else {
+ lcd.print("failed to connect");
+ }
+ if (returnCode==201) {
+ lcd.print("Data uploaded");
+ lcd.setCursor(0, 1);
+ lcd.print("Session Created");
+ return true;
+ }
+ else {
+ lcd.print("ERROR: Server returned ");
+ lcd.setCursor(0, 1);
+ lcd.print(returnCode);
+ return false;
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.