/// <summary> /// Parse Http response string and return a ThingSpeakHttpResponse object /// </summary> /// <param name="response">Http response string</param> /// <returns>ThingSpeakHttpResponse object</returns> internal static ThingSpeakHttpResponse Parse(string response) { ThingSpeakHttpResponse httpResponse = new ThingSpeakHttpResponse(); int i = 0; int headerSize = 0; // split response lines on line feed string[] lines = response.Split(LF); // trim line on carriage return lines[i] = lines[i].TrimEnd(CR); // headers end with empty string while (lines[i] != String.Empty) { // calculate header size headerSize += lines[i].Length + CRLF.Length; int separatorIndex = lines[i].IndexOf(":"); // first line contains Http response code if (i == 0) { httpResponse.ResponseCode = lines[i]; httpResponse.StatusCode = Convert.ToInt32(httpResponse.ResponseCode.Substring(httpResponse.ResponseCode.IndexOf(' ') + 1, 3)); } // found header-value separator else if (separatorIndex != -1) httpResponse.Headers.Add(lines[i].Substring(0, separatorIndex), lines[i].Substring(separatorIndex + 1).Trim()); i++; // trim end carriage return of each line lines[i] = lines[i].TrimEnd(CR); } // next line (body start) i++; // set start of body inside response int bodyOffset = headerSize + CRLF.Length; // get body from entire response string body = response.Substring(bodyOffset); // content length specified if (httpResponse.Headers.Contains("Content-Length")) { httpResponse.Body = body.Substring(0, Convert.ToInt32(httpResponse.Headers["Content-Length"].ToString())); } // transfer encoding specified else if (httpResponse.Headers.Contains("Transfer-Encoding")) { // body chunked if (httpResponse.Headers["Transfer-Encoding"].ToString() == "chunked") { httpResponse.Body = String.Empty; int chunkDim = 0; int currBodyOffset = 0; do { // get chunk dimension chunkDim = Convert.ToInt32(body.Substring(0, body.IndexOf(CRLF)), 16); // get the following body chunk if (chunkDim != 0) { // set offset after chunk dimension currBodyOffset = body.IndexOf(CRLF) + CRLF.Length; // get the body chunk httpResponse.Body += body.Substring(currBodyOffset, chunkDim); // update body part to analize body = body.Substring(currBodyOffset + chunkDim + CRLF.Length); } } while (chunkDim != 0); // trim last CRLF of body httpResponse.Body = httpResponse.Body.TrimEnd(LF).TrimEnd(CR); } } return httpResponse; }
/// <summary> /// Update a channel /// </summary> /// <param name="writeApiKey">Write API Key for the channel to update</param> /// <param name="dataEntry">Data entry for updating channel</param> /// <returns>Update result</returns> public bool Update( string writeApiKey, DataEntry dataEntry) { // check for a mandatory write API Key if ((writeApiKey == null) || (writeApiKey == String.Empty)) { throw new ArgumentNullException("writeApiKey", "You must specify a write API Key"); } // check max fields number if (dataEntry.Fields.Length > THING_SPEAK_MAX_FIELDS) { throw new ArgumentException("fields", "Max number of field is " + THING_SPEAK_MAX_FIELDS); } // check at leaset one field value not empty bool checkFields = false; for (int i = 0; i < dataEntry.Fields.Length; i++) { if (dataEntry.Fields[i] != null) { checkFields = true; break; } } if (!checkFields) { throw new ArgumentNullException("fields", "You must specify a field value at least"); } // check status message if ((dataEntry.Status != null) && (dataEntry.Status.Length > THING_SPEAK_MAX_STATUS)) { throw new ArgumentException("status", "Max status length is " + THING_SPEAK_MAX_STATUS); } // check twitter account and message if (((dataEntry.Twitter == null) && (dataEntry.Tweet != null)) || ((dataEntry.Twitter != null) && (dataEntry.Tweet == null))) { throw new ArgumentException("twitter and tweet parameters must be both valued"); } // build body string body = String.Empty; // fields... for (int i = 0; i < dataEntry.Fields.Length; i++) { if ((dataEntry.Fields[i] != null) && (dataEntry.Fields[i] != String.Empty)) { if (i > 0) { body += "&"; } body += "field" + (i + 1) + "=" + dataEntry.Fields[i]; } } // ...location... if (dataEntry.Location != null) { body += "&lat=" + dataEntry.Location.Latitude + "&long=" + dataEntry.Location.Longitude + "&elevation=" + dataEntry.Location.Elevation; } // ...status... if (dataEntry.Status != null) { body += "&status=" + dataEntry.Status; } // ...twitter... if ((dataEntry.Twitter != null) && (dataEntry.Tweet != null)) { body += "&twitter=" + dataEntry.Twitter + "&tweet=" + dataEntry.Tweet; } // build HTTP request string request = "POST " + THING_SPEAK_UPDATE_PATH + " HTTP/1.1" + CRLF; request += "Host: " + THING_SPEAK_HOST + CRLF; request += "Connection: close" + CRLF; request += "X-THINGSPEAKAPIKEY: " + writeApiKey + CRLF; request += "Content-Type: application/x-www-form-urlencoded" + CRLF; request += "Content-Length: " + body.Length + CRLF; request += CRLF; request += body + CRLF; string result = String.Empty; // open socket e connect to the host using (this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { this.socket.Connect(this.hostIpEndPoint); // send HTTP request this.sendBuffer = Encoding.UTF8.GetBytes(request); if (this.SSL) { // TODO : HTTPS communication } else { // send HTTP request this.socket.Send(this.sendBuffer); // receive HTTP response this.receiveBuffer = new byte[RECEIVE_BUFFER_SIZE]; // poll on socket for reading (timeout 30 sec) while (this.socket.Poll(30 * 1000000, SelectMode.SelectRead)) { // no data on th socket (closed or timeout) if (this.socket.Available == 0) { break; } // empty buffer Array.Clear(this.receiveBuffer, 0, this.receiveBuffer.Length); // read data this.socket.Receive(this.receiveBuffer); // append response result += new String(Encoding.UTF8.GetChars(this.receiveBuffer)); } } } // decode HTTP response ThingSpeakHttpResponse httpResponse = ThingSpeakHttpResponse.Parse(result); Debug.Print(result); if (httpResponse.StatusCode == 200) { // set entry Id received from the server dataEntry.Id = Convert.ToInt32(httpResponse.Body); return(true); } else { return(false); } }
/// <summary> /// Parse Http response string and return a ThingSpeakHttpResponse object /// </summary> /// <param name="response">Http response string</param> /// <returns>ThingSpeakHttpResponse object</returns> internal static ThingSpeakHttpResponse Parse(string response) { ThingSpeakHttpResponse httpResponse = new ThingSpeakHttpResponse(); int i = 0; int headerSize = 0; // split response lines on line feed string[] lines = response.Split(LF); // trim line on carriage return lines[i] = lines[i].TrimEnd(CR); // headers end with empty string while (lines[i] != String.Empty) { // calculate header size headerSize += lines[i].Length + CRLF.Length; int separatorIndex = lines[i].IndexOf(":"); // first line contains Http response code if (i == 0) { httpResponse.ResponseCode = lines[i]; httpResponse.StatusCode = Convert.ToInt32(httpResponse.ResponseCode.Substring(httpResponse.ResponseCode.IndexOf(' ') + 1, 3)); } // found header-value separator else if (separatorIndex != -1) { httpResponse.Headers.Add(lines[i].Substring(0, separatorIndex), lines[i].Substring(separatorIndex + 1).Trim()); } i++; // trim end carriage return of each line lines[i] = lines[i].TrimEnd(CR); } // next line (body start) i++; // set start of body inside response int bodyOffset = headerSize + CRLF.Length; // get body from entire response string body = response.Substring(bodyOffset); // content length specified if (httpResponse.Headers.Contains("Content-Length")) { httpResponse.Body = body.Substring(0, Convert.ToInt32(httpResponse.Headers["Content-Length"].ToString())); } // transfer encoding specified else if (httpResponse.Headers.Contains("Transfer-Encoding")) { // body chunked if (httpResponse.Headers["Transfer-Encoding"].ToString() == "chunked") { httpResponse.Body = String.Empty; int chunkDim = 0; int currBodyOffset = 0; do { // get chunk dimension chunkDim = Convert.ToInt32(body.Substring(0, body.IndexOf(CRLF)), 16); // get the following body chunk if (chunkDim != 0) { // set offset after chunk dimension currBodyOffset = body.IndexOf(CRLF) + CRLF.Length; // get the body chunk httpResponse.Body += body.Substring(currBodyOffset, chunkDim); // update body part to analize body = body.Substring(currBodyOffset + chunkDim + CRLF.Length); } } while (chunkDim != 0); // trim last CRLF of body httpResponse.Body = httpResponse.Body.TrimEnd(LF).TrimEnd(CR); } } return(httpResponse); }
/// <summary> /// Read channel data entries /// </summary> /// <param name="readApiKey">Read API Key for the channel to read (null if channel is public)</param> /// <param name="channelId">Channel ID</param> /// <param name="path">Path for reading channel</param> /// <returns>List of all data entries read</returns> private ArrayList ReadChannel(string readApiKey, int channelId, string path) { // build HTTP request string request = "GET /channels/" + channelId + path + " HTTP/1.1" + CRLF; request += "Host: " + THING_SPEAK_HOST + CRLF; request += "Connection: close" + CRLF; if ((readApiKey != null) && (readApiKey != String.Empty)) { request += "X-THINGSPEAKAPIKEY: " + readApiKey + CRLF; } request += CRLF; string result = String.Empty; // open socket e connect to the host using (this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { this.socket.Connect(this.hostIpEndPoint); this.sendBuffer = Encoding.UTF8.GetBytes(request); if (this.SSL) { // TODO : HTTPS communication } else { // send HTTP request this.socket.Send(this.sendBuffer); // receive HTTP response this.receiveBuffer = new byte[RECEIVE_BUFFER_SIZE]; // poll on socket for reading (timeout 30 sec) while (this.socket.Poll(30 * 1000000, SelectMode.SelectRead)) { // no data on th socket (closed or timeout) if (this.socket.Available == 0) { break; } // empty buffer Array.Clear(this.receiveBuffer, 0, this.receiveBuffer.Length); // read data this.socket.Receive(this.receiveBuffer); // append response result += new String(Encoding.UTF8.GetChars(this.receiveBuffer)); } } } // decode HTTP response ThingSpeakHttpResponse httpResponse = ThingSpeakHttpResponse.Parse(result); Debug.Print(result); if (httpResponse.StatusCode == 200) { return(DataEntry.ParseCsv(httpResponse.Body)); } else { return(null); } }