Last active
August 29, 2015 14:25
-
-
Save xaguzman/c9217395b1870ce9bca2 to your computer and use it in GitHub Desktop.
IoT Campus Party 2015
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
/* | |
* IoT Dimmer | |
* | |
* This sketch connects to a control site using an Arduino Wiznet | |
* Ethernet shield and outputs the directed intensity as a binary | |
* number on pins 5 - 7, where Most Significant bit is 7. | |
* | |
* Circuit: | |
* Ethernet shield attached to pins 10, 11, 12, 13 | |
* | |
* Created July 9th, 2015 | |
* by Ulises Ruiz, Juan Romero and Xavier Guzman. | |
* | |
* Copyright (c) 2015 Grupo Flextronics, S.A. de C.V. | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* 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. | |
* | |
*/ | |
#include <SPI.h> | |
#include <Ethernet.h> | |
// Constants | |
#define MAX_BUFFER 128 | |
#define SIGNIFICANCE_1 5 | |
#define SIGNIFICANCE_2 6 | |
#define SIGNIFICANCE_3 7 | |
#define SIGNAL_PIN 8 | |
#define ETHERNET_SDCARD_SELECTOR 4 | |
//byte MAC_ADDRESS[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; | |
byte MAC_ADDRESS[] = { 0, 0}; //place your mac address here. | |
//char* DEVICE_NAME = "device1"; | |
char* DEVICE_NAME = ""; //select your own device | |
char* CONTROL_SERVER_ADDRESS = "iot-prod-vm-wus.cloudapp.net"; | |
char* VALID_TOKEN = "{letmein"; | |
int CONTROL_SERVER_PORT = 9000; | |
// Global Variables. | |
EthernetClient client; | |
void setup() { | |
// Open serial communications and wait for port to open: | |
Serial.begin(9600); | |
while (!Serial) { | |
; // wait for serial port to connect. Needed for Leonardo only | |
} | |
// Set all pins to output mode | |
pinMode(SIGNIFICANCE_1, OUTPUT); | |
pinMode(SIGNIFICANCE_2, OUTPUT); | |
pinMode(SIGNIFICANCE_3, OUTPUT); | |
pinMode(SIGNAL_PIN, OUTPUT); | |
// Turn off light initially | |
outputIntensity(0); | |
turnSignal(HIGH); | |
Serial.println("Waiting for DHCP..."); | |
// start the Ethernet connection: | |
while (Ethernet.begin(MAC_ADDRESS) == 0) { | |
Serial.println("Failed to configure Ethernet using DHCP!"); | |
delay(1000); | |
Serial.println("Retrying DHCP..."); | |
} | |
Serial.print("DHCP Initialized. IP Address is: "); Serial.println(Ethernet.localIP()); | |
// Give the Ethernet shield a second to initialize: | |
delay(1000); | |
} | |
void loop() | |
{ | |
Serial.println("Connecting to control server:"); | |
char* receiveBuffer = (char*)malloc(MAX_BUFFER); | |
int receiveBufferIndex = 0; | |
if (client.connect(CONTROL_SERVER_ADDRESS, CONTROL_SERVER_PORT)) { | |
delay(1000); | |
Serial.println("Connected. Waiting for commands..."); | |
turnSignal(LOW); // We are connected so set setup signal to off | |
while(true) { | |
while (client.available()) { | |
char incomingChar = client.read(); | |
receiveBuffer[receiveBufferIndex ++] = incomingChar; | |
if(receiveBufferIndex > 2) { | |
if(receiveBuffer[receiveBufferIndex - 2] == '\r' && receiveBuffer[receiveBufferIndex - 1] == '\n') { | |
receiveBuffer[receiveBufferIndex] = 0; | |
handleServerCommand(receiveBuffer); ; | |
receiveBufferIndex = 0; | |
} | |
} | |
delay(10); | |
} // while(client.available()) | |
} // while (true) | |
} else { | |
Serial.println("connection failed"); | |
delay(5000); | |
} | |
} | |
void handleServerCommand(char* serverMessage) | |
{ | |
Serial.print("Received message from control server: "); | |
Serial.println(serverMessage); | |
int serverMessageLength = strlen(serverMessage); | |
int tokenLength = strlen(VALID_TOKEN); | |
if(serverMessageLength > tokenLength) { | |
char* indexOfColon = strchr(serverMessage, ':'); | |
if(indexOfColon != NULL ) { | |
*indexOfColon = 0; | |
char* seekPointer = indexOfColon + 1; | |
if(!strcmp(serverMessage, VALID_TOKEN)) { | |
while(isspace(*seekPointer)) seekPointer ++; | |
char* indexOfEqualTo = strchr(seekPointer, '='); | |
if(indexOfEqualTo != NULL ) { | |
*indexOfEqualTo = 0; | |
indexOfEqualTo ++; | |
if(!strcmp(seekPointer, DEVICE_NAME)) { | |
int intensityValue = *indexOfEqualTo - '0'; | |
if(intensityValue >= 0 && intensityValue <= 7) { | |
outputIntensity(intensityValue); | |
} else { | |
Serial.print("Invalid message: Invalid intensity: "); Serial.println(intensityValue); | |
} | |
} else { | |
Serial.print("Invalid message: Missmatch device name: "); Serial.println(seekPointer); | |
} | |
} else { | |
Serial.println("Invalid message: No '='"); | |
} | |
} else { | |
Serial.println("Invalid message: invalid token"); | |
} | |
} else { | |
Serial.println("Invalid message: No ':'"); | |
} | |
} else { | |
Serial.println("Invalid message: Size is "); Serial.println(serverMessageLength); | |
} | |
} | |
void outputIntensity(int intensity) | |
{ | |
Serial.print("Changing intensity to: "); Serial.println(intensity); | |
digitalWrite(SIGNIFICANCE_1, intensity & 0x01? LOW : HIGH); | |
digitalWrite(SIGNIFICANCE_2, intensity & 0x02? LOW : HIGH); | |
digitalWrite(SIGNIFICANCE_3, intensity & 0x04? LOW : HIGH); | |
} | |
void turnSignal(int state) { | |
digitalWrite(SIGNAL_PIN, state); | |
} | |
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
/* | |
* IoT Dimmer Android client | |
* | |
* This program implements: | |
* - An Android app to send control requests to the control server. The app shows a slider | |
* with values from 0 to 7. | |
* | |
* Created July 9th, 2015 | |
* by Ulises Ruiz, Juan Romero and Xavier Guzman. | |
* | |
* Copyright (c) 2015 Grupo Flextronics, S.A. de C.V. | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* 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. | |
* | |
*/ | |
package com.flextronics.iot.Dimmer; | |
import android.app.Activity; | |
import android.os.AsyncTask; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.widget.SeekBar; | |
import android.widget.TextView; | |
import java.io.*; | |
import java.net.HttpURLConnection; | |
import java.net.URL; | |
public class DimmerActivity extends Activity { | |
TextView txtResponse; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main); | |
SeekBar bar = (SeekBar)findViewById(R.id.seekBar); | |
final TextView txt = (TextView)findViewById(R.id.txtValue); | |
txt.setText(String.valueOf(bar.getProgress())); | |
txtResponse = (TextView)findViewById(R.id.txtResponse); | |
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { | |
@Override | |
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } | |
@Override | |
public void onStartTrackingTouch(SeekBar seekBar) { } | |
@Override | |
public void onStopTrackingTouch(SeekBar seekBar) { | |
String progress = String.valueOf( seekBar.getProgress() ); | |
txt.setText(progress); | |
txtResponse.setText("Please wait..."); | |
new SendRequestTask().execute(getString(R.string.host), progress); | |
} | |
}); | |
} | |
private class SendRequestTask extends AsyncTask<String, Void, String>{ | |
private static final String token = "letmein"; | |
private static final String target = "device1"; | |
@Override | |
protected String doInBackground(String... params) { | |
String queryString = String.format("?intensity=%s&token=%s&device=%s", params[1], token, target); | |
String requestUrl = params[0] + queryString; | |
// params comes from the execute() call: params[0] is the url. | |
String res = ""; | |
String responseCode ="" ; | |
try { | |
Log.d("Dimmer", "Sending request " + requestUrl); | |
HttpURLConnection urlConnection = (HttpURLConnection) new URL(requestUrl).openConnection(); | |
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); | |
StringBuilder builder = new StringBuilder(); | |
String line; | |
while ( (line = reader.readLine()) != null){ | |
builder.append(line); | |
} | |
res = builder.toString(); | |
urlConnection.disconnect(); | |
responseCode = urlConnection.getResponseMessage(); | |
} catch (IOException e) { | |
res = e.getMessage(); | |
} finally{ | |
return responseCode; | |
} | |
} | |
@Override | |
protected void onPostExecute(String result) { | |
Log.d("Dimmer", "Response was " + result); | |
txtResponse.setText(result); | |
} | |
} | |
} |
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
/* | |
* IoT Dimmer Control Server | |
* | |
* This program implements: | |
* - An HTTP server to receive control requests from a phone | |
* or a web browser and puts them in a queue. | |
* - A text server for Arduino clients that get a copy of the queued | |
* messages. | |
* | |
* This server is intended to be deployed as a cloud service. | |
* | |
* Created July 9th, 2015 | |
* by Ulises Ruiz, Juan Romero and Xavier Guzman. | |
* | |
* Copyright (c) 2015 Grupo Flextronics, S.A. de C.V. | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* 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. | |
* | |
*/ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Flextronics.CampusParty.Server; | |
using System.Net.Sockets; | |
using System.Net; | |
using System.IO; | |
using System.Collections.Specialized; | |
using System.Web; | |
namespace Flextronics.CampusParty.Server.IoTWorkshopCloudServer | |
{ | |
class Program | |
{ | |
private static readonly string bindAddressHttp = "tcp://0.0.0.0:8080"; | |
private static readonly string bindAddressArduino = "tcp://0.0.0.0:9000"; | |
private static readonly string HTTP_VERB_GET = "GET"; | |
private static readonly string HTTP_REQUEST_ADDRESS = "/iotdimmer"; | |
private static readonly string VALID_TOKEN = "letmein"; | |
private static readonly string HTTP_PARAM_INTENSITY = "intensity"; | |
private static readonly string HTTP_PARAM_TOKEN = "token"; | |
private static readonly string HTTP_PARAM_TARGET = "device"; | |
private static Dictionary<string, int> controlRequests = new Dictionary<string, int>(); | |
private static List<TcpClient> arduinoClients = new List<TcpClient>(); | |
private static ASCIIEncoding asciiEncoding = new ASCIIEncoding(); | |
static void Main(string[] args) | |
{ | |
TcpListener httpListener = null; | |
TcpListener arduinoListener = null; | |
System.Console.WriteLine("Initializing..."); | |
httpListener = startListener(bindAddressHttp); | |
arduinoListener = startListener(bindAddressArduino); | |
System.Console.WriteLine("Listening for HTTP and Arduino clients. Press [Ctrl] + [Q] to quit:"); | |
communicationLoop(httpListener, arduinoListener); | |
System.Console.WriteLine("Quit message received - Shutting down:"); | |
closeListener(httpListener); | |
closeListener(arduinoListener); | |
foreach (TcpClient client in arduinoClients) | |
{ | |
try | |
{ | |
if (IsConnected(client.Client)) | |
{ | |
client.Close(); | |
} | |
} | |
catch (Exception ex) | |
{ | |
System.Console.WriteLine("WARNINIG: Arduino Connection Close: " + ex.Message); | |
System.Console.WriteLine(ex.ToString()); | |
} | |
} | |
arduinoClients.Clear(); | |
System.Console.WriteLine("Shut down completed"); | |
} | |
private static void closeListener(TcpListener listener) | |
{ | |
listener.Stop(); | |
listener = null; | |
} | |
private static void communicationLoop(TcpListener httpListener, TcpListener arduinoListener) | |
{ | |
bool quitMessageReceived = false; | |
while (!quitMessageReceived) | |
{ | |
if (httpListener.Pending()) | |
try | |
{ | |
TcpClient httpClient = httpListener.AcceptTcpClient(); | |
NetworkStream networkStream = httpClient.GetStream(); | |
System.Console.WriteLine("Accepted HTTP client: " + | |
httpClient.Client.RemoteEndPoint); | |
handleHttpClient(networkStream); | |
networkStream.Flush(); | |
networkStream.Close(); | |
httpClient.Close(); | |
} | |
catch (Exception ex) | |
{ | |
System.Console.WriteLine("WARNINIG: HTTP Connection: " + ex.Message); | |
System.Console.WriteLine(ex.ToString()); | |
} | |
if (arduinoListener.Pending()) | |
{ | |
try | |
{ | |
TcpClient arduinoClient = arduinoListener.AcceptTcpClient(); | |
System.Console.WriteLine("Accepted Arduino client: " + | |
arduinoClient.Client.RemoteEndPoint); | |
arduinoClients.Add(arduinoClient); | |
} | |
catch (Exception ex) | |
{ | |
System.Console.WriteLine("WARNINIG: Arduino Connection: " + ex.Message); | |
System.Console.WriteLine(ex.ToString()); | |
} | |
} | |
List<TcpClient> disconnectedClients = new List<TcpClient>(); | |
if (controlRequests.Count > 0) | |
{ | |
bool didDeliverAtLeastOneMessage = false; | |
foreach (TcpClient client in arduinoClients) | |
{ | |
try | |
{ | |
if (IsConnected(client.Client)) | |
{ | |
System.Console.WriteLine( | |
"Attempting to send control requests to " + | |
client.Client.RemoteEndPoint); | |
foreach (KeyValuePair<string, int> request in controlRequests) | |
{ | |
NetworkStream networkStream = client.GetStream(); | |
if (networkStream.CanWrite) | |
{ | |
System.Console.WriteLine("\t" + | |
client.Client.RemoteEndPoint + ": " + | |
request.Key + " = " + request.Value); | |
sendArduinoControlRequest(networkStream, request.Key, | |
request.Value); | |
networkStream.Flush(); | |
didDeliverAtLeastOneMessage = true; | |
} | |
else | |
{ | |
System.Console.WriteLine("Marking " + | |
client.Client.RemoteEndPoint + | |
" as disconnected"); | |
disconnectedClients.Add(client); | |
} | |
} | |
} | |
else | |
{ | |
System.Console.WriteLine("Marking " + client.Client.RemoteEndPoint + | |
" as disconnected"); | |
disconnectedClients.Add(client); | |
} | |
} | |
catch (Exception ex) | |
{ | |
System.Console.WriteLine("Marking " + client.Client.RemoteEndPoint + | |
" as disconnected due to exception: " + | |
ex.Message); | |
disconnectedClients.Add(client); | |
} | |
} | |
if (didDeliverAtLeastOneMessage) | |
{ | |
System.Console.WriteLine("Clearing control requests cache"); | |
controlRequests.Clear(); | |
} | |
foreach (TcpClient disconnectedClient in disconnectedClients) | |
{ | |
arduinoClients.Remove(disconnectedClient); | |
} | |
} | |
if (System.Console.KeyAvailable) | |
{ | |
ConsoleKeyInfo cki = System.Console.ReadKey(true); | |
quitMessageReceived = cki.Key == ConsoleKey.Q && // [Ctrl] + [Q] | |
cki.Modifiers.HasFlag(ConsoleModifiers.Control); | |
} | |
System.Threading.Thread.Sleep(100); | |
} | |
} | |
private static bool IsConnected(Socket socket) | |
{ | |
try | |
{ | |
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0); | |
} | |
catch (SocketException) | |
{ | |
return (false); | |
} | |
} | |
private static TcpListener startListener(string uriString) | |
{ | |
TcpListener listener = null; | |
Uri uri = new Uri(uriString); | |
IPAddress bindAddress = IPAddress.Parse(uri.Host); | |
IPEndPoint endPoint = new IPEndPoint(bindAddress, uri.Port); | |
listener = new TcpListener(endPoint); | |
listener.Start(); | |
return (listener); | |
} | |
private static void handleHttpClient(NetworkStream stream) | |
{ | |
Func<NameValueCollection, bool> containsAllParamas = (requestParameters) => | |
{ | |
// Are there parameters in query string? | |
if (requestParameters != null) | |
// Is the intensity parameter present? | |
if (requestParameters.AllKeys.Contains(HTTP_PARAM_INTENSITY)) | |
// Is the access token present? | |
if (requestParameters.AllKeys.Contains(HTTP_PARAM_TOKEN)) | |
// Is the target parameter present? | |
if (requestParameters.AllKeys.Contains(HTTP_PARAM_TARGET)) | |
return (true); | |
return (false); | |
}; | |
string httpRequest = receiveHttpRequest(stream); | |
if (httpRequest.Length > 0) | |
{ | |
string[] requestLines = httpRequest.Split(new string[] { "\r\n" }, | |
StringSplitOptions.RemoveEmptyEntries); | |
if (requestLines.Length > 0) | |
{ | |
string message = requestLines[0]; | |
string[] messagePieces = message.Split(new string[] { " " }, | |
StringSplitOptions.RemoveEmptyEntries); | |
//if (messagePieces.Length > 1) | |
//{ | |
string verb = messagePieces[0]; | |
// /dimmer?intensity=5&token=letmein&target=sample1 | |
string requestUri = messagePieces[1]; | |
string htppSignature = messagePieces[2]; | |
string address = null; | |
NameValueCollection requestParameters = null; | |
if (requestUri.Contains("/")) | |
{ | |
if (requestUri.Contains("?")) | |
{ | |
address = requestUri.Substring(requestUri.IndexOf("/"), requestUri.IndexOf("?")); | |
string queryString = requestUri.Substring(requestUri.IndexOf("?") + 1); | |
requestParameters = HttpUtility.ParseQueryString(queryString); | |
} | |
else | |
{ | |
address = requestUri.Substring(requestUri.IndexOf("/")); | |
} | |
} | |
if (verb == HTTP_VERB_GET) | |
{ | |
// Is the resource ok? http://<server>/resource | |
if (address.Trim().ToLower() == HTTP_REQUEST_ADDRESS) | |
{ | |
if (containsAllParamas(requestParameters)) | |
{ | |
string intensity = requestParameters[HTTP_PARAM_INTENSITY]; | |
string token = requestParameters[HTTP_PARAM_TOKEN]; | |
string target = requestParameters[HTTP_PARAM_TARGET]; | |
int intensityData; | |
if (Int32.TryParse(intensity, out intensityData)) | |
{ | |
if (token == VALID_TOKEN) // Is the access token the righg one? | |
{ | |
string response = "<HEAD>" + Environment.NewLine; | |
response += "</HEAD>" + Environment.NewLine; | |
response += "<BODY>" + Environment.NewLine; | |
if (intensityData >= 0 && intensityData <= 7) | |
{ | |
if (controlRequests.ContainsKey(target)) | |
{ | |
int previousValue = controlRequests[target]; | |
controlRequests[target] = intensityData; | |
response += "Received command: " + target + | |
" will switch intencity to " + | |
intensityData.ToString() + " instead of " + | |
previousValue.ToString(); | |
} | |
else | |
{ | |
controlRequests.Add(target, intensityData); | |
response += "Received command: " + target + | |
" will switch intencity to " + | |
intensityData.ToString(); | |
} | |
} | |
System.Console.WriteLine(response); | |
response += generateControlPage(token, target); | |
response += "</BODY>" + Environment.NewLine; | |
writeHttpSuccessHtmlResponse(stream, response); | |
return; | |
} | |
else // The token is not right! | |
{ | |
writeHttpErrorResponse(stream, 403, "Forbidden"); | |
return; | |
} | |
} | |
else // Unable to parse intensity! | |
{ | |
writeHttpErrorResponse(stream, 416, "Requested Range Not Satisfiable"); | |
return; | |
} | |
} | |
} | |
else // Not the right resource! | |
{ | |
writeHttpErrorResponse(stream, 404, "Not found"); | |
return; | |
} | |
} | |
else // Not a GET verb! | |
{ | |
writeHttpErrorResponse(stream, 405, "Method not allowed"); | |
return; | |
} | |
} | |
//} | |
} | |
// Request was not understood! | |
writeHttpErrorResponse(stream, 400, "Bad request"); | |
} | |
private static string generateControlPage(string token, string target) | |
{ | |
StringBuilder response = new StringBuilder(); | |
response.AppendLine("<br><br><b>Select intensity:</b><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=0&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Off</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=1&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 1</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=2&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 2</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=3&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 3</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=4&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 4</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=5&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 5</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=6&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 6</a><br>"); | |
response.Append("<a href = '/iotdimmer?intensity=7&token=").Append(token).Append("&device="). | |
Append(target).AppendLine("'>Intensity 7</a><br>"); | |
return (response.ToString()); | |
} | |
private static void writeHttpErrorResponse(NetworkStream stream, int errorCode, string errorMessage) | |
{ | |
StreamWriter outputStream = new StreamWriter(new BufferedStream(stream)); | |
outputStream.WriteLine("HTTP/1.0 " + errorCode.ToString() + " " + errorMessage); | |
outputStream.WriteLine("Connection: close"); | |
outputStream.WriteLine(""); | |
outputStream.Flush(); | |
} | |
private static void writeHttpSuccessHtmlResponse(NetworkStream stream, string htmlBody) | |
{ | |
StreamWriter outputStream = new StreamWriter(new BufferedStream(stream)); | |
outputStream.WriteLine("HTTP/1.0 200 OK"); | |
outputStream.WriteLine("Content-Type: text/html"); | |
outputStream.WriteLine("Connection: close"); | |
outputStream.WriteLine(""); | |
outputStream.WriteLine("<!DOCTYPE HTML>"); | |
outputStream.WriteLine("<HTML>"); | |
outputStream.Write(htmlBody); | |
outputStream.WriteLine("</HTML>"); | |
outputStream.Flush(); | |
} | |
private static void sendAsciiMessage(NetworkStream stream, string asciiMessage) | |
{ | |
StreamWriter writer = new StreamWriter(stream); | |
writer.WriteLine(asciiMessage); | |
} | |
private static string receiveHttpRequest(NetworkStream stream) | |
{ | |
StringBuilder message = new StringBuilder(); | |
StreamReader reader = new StreamReader(stream); | |
bool readToEnd = false; | |
string line = reader.ReadLine(); | |
if (line != null) message.AppendLine(line); | |
while (line != null && !readToEnd) | |
{ | |
line = reader.ReadLine(); | |
readToEnd = line == null || line.Length == 0; | |
if (!readToEnd) message.AppendLine(line); | |
} | |
return (message.ToString()); | |
} | |
private static void sendArduinoControlRequest(NetworkStream stream, string target, int intensity) | |
{ | |
StreamWriter outputStream = new StreamWriter(new BufferedStream(stream)); | |
outputStream.WriteLine("{" + VALID_TOKEN + ": " + target + "=" + intensity.ToString() + "}"); | |
outputStream.Flush(); | |
} | |
} | |
} |
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
/* | |
* IoT Dimmer Light Test | |
* | |
* This sketch connects to a control site using an Arduino Wiznet | |
* Ethernet shield and outputs the directed intensity as a binary | |
* number on pins 5 - 7, where Most Significant bit is 7. | |
* | |
* Circuit: | |
* Ethernet shield attached to pins 10, 11, 12, 13 | |
* | |
* Created July 9th, 2015 | |
* by Ulises Ruiz, Juan Romero and Xavier Guzman. | |
* | |
* Copyright (c) 2015 Grupo Flextronics, S.A. de C.V. | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* 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. | |
* | |
*/ | |
// Pin 13 has an LED connected on most Arduino boards. | |
// give it a name: | |
// the setup routine runs once when you press reset: | |
void setup() { | |
// initialize the digital pin as an output. | |
pinMode(5, OUTPUT); | |
pinMode(6, OUTPUT); | |
pinMode(7, OUTPUT); | |
pinMode(8, OUTPUT); | |
turnSignal(HIGH); | |
} | |
// the loop routine runs over and over again forever: | |
void loop() { | |
outputIntensity(0);delay(1000); // wait for a second | |
turnSignal(LOW); | |
outputIntensity(1);delay(1000); // wait for a second | |
turnSignal(HIGH); | |
outputIntensity(2);delay(1000); // wait for a second | |
turnSignal(LOW); | |
outputIntensity(3);delay(1000); // wait for a second | |
turnSignal(HIGH); | |
outputIntensity(4);delay(1000); // wait for a second | |
turnSignal(LOW); | |
outputIntensity(5);delay(1000); // wait for a second | |
turnSignal(HIGH); | |
outputIntensity(6);delay(1000); // wait for a second | |
turnSignal(LOW); | |
outputIntensity(7);delay(1000); // wait for a second | |
turnSignal(HIGH); | |
} | |
void outputIntensity(int intensity) | |
{ | |
Serial.print("Changing intensity to: "); Serial.println(intensity); | |
digitalWrite(5, intensity & 0x01? HIGH : LOW); | |
digitalWrite(6, intensity & 0x02? HIGH : LOW); | |
digitalWrite(7, intensity & 0x04? HIGH : LOW); | |
} | |
void turnSignal(int state) { | |
digitalWrite(8, state); | |
} |
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
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:orientation="vertical" | |
android:layout_width="fill_parent" | |
android:layout_height="fill_parent" | |
android:weightSum="1" android:columnCount="10" android:rowCount="10"> | |
<TextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:textAppearance="?android:attr/textAppearanceLarge" | |
android:text="@string/app_title" | |
android:id="@+id/txtTitle" android:gravity="center"/> | |
<EditText | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:id="@+id/editText" | |
android:text="@string/host" | |
android:visibility="invisible"/> | |
<Space | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_weight="0.25"/> | |
<SeekBar | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:id="@+id/seekBar" android:thumbOffset="1dp" android:longClickable="false" android:max="7"/> | |
<LinearLayout | |
android:orientation="horizontal" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" android:paddingTop="15dp" | |
android:paddingLeft="10dp"> | |
<TextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:textAppearance="?android:attr/textAppearanceMedium" | |
android:text="Intensity:" | |
android:id="@+id/textView" android:layout_marginRight="3dp"/> | |
<TextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:textAppearance="?android:attr/textAppearanceSmall" | |
android:text="<value>" | |
android:id="@+id/txtValue"/> | |
</LinearLayout> | |
<TextView | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:id="@+id/txtResponse" android:layout_gravity="center_horizontal" android:layout_weight="0.72"/> | |
</LinearLayout> |
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
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<string name="app_name">Dimmer</string> | |
<string name="app_title">IOT DIMMER</string> | |
<string name="host">http://iot-prod-vm-wus.cloudapp.net:8080/iotdimmer</string> | |
</resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment