Smart Beer

My first project using an Arduino micro-controller. Detect when my glass is getting low on beer and then send a message indicating I need a refill! The message can be sent using either Cisco Spark (demoed in the below video) or Twitter.



Yes, I'm using a straw with beer. Don't judge. How else am I supposed to do this on camera? Maybe the next version it will be integrated in the glass...

There was some issue with fluctuating sensor readings. Perhaps the beer had too much carbonation which affected the analog water sensor (it worked much better in plain water). Maybe I'll try again with wine next time.

Electrical Connections

Fairly straightforward here.

Arduino Code

This is also using an Ethernet shield attached to the base Arduino board. However since the ethernet shield cannot natively handle HTTPS (!) the code is calling a local web server which in turn will proxy the specific request to either Twitter or Cisco Spark to actually post the message securely.
#include <SPI.h> #include <Ethernet.h> #include <HttpClient.h> // Enter a MAC address for your controller byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // Initialize the Ethernet client library EthernetClient client; bool messageSent1; bool messageSent2; void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); pinMode(9,OUTPUT); Serial.println("Starting ethernet"); Ethernet.begin(mac); messageSent1 = false; messageSent2 = false; Serial.println("Setup complete"); } void loop() { switch (Ethernet.maintain()) { case 1: //renewed fail Serial.println("Error: renewed fail"); break; case 2: //renewed success Serial.println("Renewed success"); break; case 3: //rebind fail Serial.println("Error: rebind fail"); break; case 4: //rebind success Serial.println("Rebind success"); break; default: break; } /* 0mm - 480 5mm - 530 10mm - 615 15mm - 660 20mm - 680 25mm - 690 30mm - 700 35mm - 705 40mm - 710 */ Serial.print("Analog signal: "); Serial.println(analogRead(A0)); delay(100); if (analogRead(A0) < 650) { digitalWrite(9,HIGH); if (!messageSent2) { String msg = "I need a refill!"; sendSpark(msg); messageSent2 = true; } } else if (analogRead(A0) < 700) { if (!messageSent1) { String msg = "Oh no, my drink is getting low!"; sendSpark(msg); messageSent1 = true; } } else { digitalWrite(9,LOW); } } void checkIP() { Serial.println("checking IP"); String localIP = DisplayAddress(Ethernet.localIP()); if (localIP == "255.255.255.255") { Serial.println(" no ip"); } else { Serial.println(" have ip"); } } void printIPAddress() { Serial.print("My IP address: "); for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.localIP()[thisByte], DEC); Serial.print("."); } Serial.println(); } String DisplayAddress(IPAddress address) { return String(address[0]) + "." + String(address[1]) + "." + String(address[2]) + "." + String(address[3]); } //client function to send/receive GET request data. void sendSpark(String message) { message = URLEncode(message); Serial.println("sending message"); String getparams = "GET /serve.php?app=arduino&function=1&msg=" + message + " HTTP/1.0"; Serial.println(getparams); if (client.connect("192.168.1.130", 80)) { //starts client connection, checks for connection Serial.println("connected"); client.println(getparams); //download text client.println(); //end of get request } else { Serial.println("connection failed"); //error message if no client connect Serial.println(); } while(client.connected() && !client.available()) delay(1); //waits for data while (client.connected() || client.available()) { //connected or data available char c = client.read(); //gets byte from ethernet buffer Serial.print(c); //prints byte to serial monitor } Serial.println("Spark message sent"); client.stop(); //stop client } //client function to send/receive GET request data. void sendTweet(String message) { message = URLEncode(message); Serial.println("sending message"); String getparams = "GET /serve.php?app=arduino&function=1&msg=" + message + " HTTP/1.0"; if (client.connect("192.168.1.130", 80)) { //starts client connection, checks for connection Serial.println("connected"); client.println(getparams); //download text client.println(); //end of get request } else { Serial.println("connection failed"); //error message if no client connect Serial.println(); } while(client.connected() && !client.available()) delay(1); //waits for data while (client.connected() || client.available()) { //connected or data available char c = client.read(); //gets byte from ethernet buffer Serial.print(c); //prints byte to serial monitor } Serial.println("Tweet sent"); client.stop(); //stop client } String URLEncode(String originalMessage) { const char* msg = originalMessage.c_str(); const char *hex = "0123456789abcdef"; String encodedMsg = ""; while (*msg!='\0'){ if( ('a' <= *msg && *msg <= 'z') || ('A' <= *msg && *msg <= 'Z') || ('0' <= *msg && *msg <= '9') ) { encodedMsg += *msg; } else { encodedMsg += '%'; encodedMsg += hex[*msg >> 4]; encodedMsg += hex[*msg & 15]; } msg++; } return encodedMsg; }

iOS Charts in Objective C Part 2

In Part 1 we discussed how to get your project ready to use Charts. In Part 2 we'll actually create some line and bar charts.

We'll be starting with the mostly blank Page View Controller presented in Part 1. The only code additions to the default application are the two import lines in ViewController.h.

Define the Data

NSArray *xaxis_data = [NSArray arrayWithObjects:@"Jan",@"Feb",@"Mar",@"Apr",@"May",nil]; NSArray *yaxis_data = [NSArray arrayWithObjects:@"5",@"10",@"15",@"10",@"20",nil];

Line Chart

LineChartView* _chartView = [[LineChartView alloc] initWithFrame:CGRectMake(20, 50, 320, 300)]; [self.view addSubview:_chartView]; _chartView.delegate = self; _chartView.descriptionText = @""; _chartView.noDataTextDescription = @"You need to provide data for the chart."; [_chartView.legend setEnabled:NO]; [_chartView.rightAxis setEnabled: NO]; // y axis on right _chartView.xAxis.drawGridLinesEnabled = NO; // vertical grid lines _chartView.xAxis.labelPosition = XAxisLabelPositionBottom; _chartView.xAxis.labelFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:10.0f]; LineChartDataSet *set1 = [[LineChartDataSet alloc] initWithYVals:y_qty2 label:@"DataSet 1"]; NSMutableArray *dataSets = [[NSMutableArray alloc] init]; [dataSets addObject:set1]; LineChartData *data = [[LineChartData alloc] initWithXVals:xaxis_data dataSets:dataSets]; _chartView.data = data;
Building and running this should produce the following:

Bar Chart

Combined Chart

iOS Charts in Objective C Part 1

I started using the Charts library for an iOS project and it has proven to be very flexible. It's based on the android library MPAndroidChart. There are a number of Java and Swift resources out there but I have not come across a basic tutorial for how to use this awesome charting library in good old fashioned Objective C.

1. Download the Charts library from Github. After unzipping the contents, open the "Charts" folder inside and drag the Charts.xcodeproject into to your own project. 2. Under the General settings for your project, scroll to the bottom and add the Charts embedded framework. 3. The latest version of Charts is written in Swift. But because we're writing in Objective C, we need to have a "bridging header" in order to be able to utilize the swift code. Fortunately this header can be created automatically. Add a new file to your project, make it of type Swift. Doesn't matter what name you give it. XCode should ask you if you would like for it to create a bridging header for you. Let it. 4. You are now ready to import the library and bridging header into your view controller. That's it! Your project is now ready to use iOS Charts, which we'll continue in Part 2.