20 Replies Latest reply on Sep 8, 2013 12:51 AM by matthew.rivett

    Arduino

    matthew.rivett

      I'm thinking of picking up an Arduino, temperature probe and network shield.  Has anyone built their own electronics and had it generate csv or some other format data to be captured by PI?  

       

      I have some ideas for things to monitor that are not part of a SCADA etc and would not make any sense for OSIsoft to build an interface for.  I think using something like the Ardiuno that you can easily program and attach sensors could be an interesting data source for PI.  It would have much smaller applications and probably more home related than business.

       

      Has anyone done something like this before?

        • Re: Arduino
          pcombellick

          Take a look at NetDuino Plus:  netduino.com/.../specs.htm

           

          It is hardware compatible with Arduino and programmable in C# and has an Ethernet connector.  Retail price is about 60USD.

           

          I have not connected mine to the PI System, but I have written software to connect to a web service.

            • Re: Arduino
              matthew.rivett

              That does look like it would be easier to work since I already know C#.  Thanks!  I think I may order one of each since the Arduino is cheap and there is more documentation for it.  If I get anything work I'll post on here however progress is going to be slow.

                • Re: Arduino
                  pcombellick

                  With NetDuino, you can debug code directly via Visual Studio (even Visual Studio Express).  Check Youtube for some interesting Arduino or Netduino videos.  www.youtube.com/watch

                    • Re: Arduino
                      matthew.rivett

                      Yeah things are busy right now.  We're moving to a new house that has a koi pond which is what I want to monitor and this seems like a fun project.  I can probably do most of it on the Arduino or NetDuino but then feeding data into a PI server could also be interesting.  I'm starting out with temperature because it should be the easiest.  Eventually I'd like to get pH, oxygen, maybe flow, level, etc.  This seems to be much more economical but a lot more work than buying a data logger.  I'll hopefully learn a lot though.

                        • Re: Arduino
                          mhamel

                          @Matt: Last year during the Connected World Conference M2M App Challenge, two hackers have used Arduino board for their project. I invite you to take a look here.

                           

                          Using AF SDK to create your "interface" to feed it your PI System would be a good option.

                            • Re: Arduino
                              matthew.rivett

                              Thanks Mathieu.  That is very interesting and will probably help a lot.  We're busy with house stuff right now but I ordered the parts.  I'm not sure when I'll start working on it.

                                • Re: Arduino
                                  matthew.rivett

                                  I am actually thinking of using PI Web Services to write the data to PI.  I should be able to write directly to PI from the Arduino that way since it doesn't require any AF or PI SDK.

                                    • Re: Arduino
                                      matthew.rivett

                                      Is there an example of how to use PI Web Services via a socket connection?  The Netduino is somewhat limited in capabilities and this appears to be one way to get this working.  I'm not too experienced with web services so I'm likely missing something.  I'm getting a 404 error.

                                       
                                              static void testweb(DateTime time)
                                              {
                                                  //pressing = data2 == 0;
                                                  String request = "POST /PITimeSeries.svc HTTP/1.1\n";
                                                  request += "Host: " + httpserver + "\n";
                                                  request += "Content-Type: text/xml; charset=utf-8\n";
                                                  request += "Content-Length: 418\n";
                                                  request += "SOAPAction: \"http://xml.osisoft.com/services/IPITimeSeries/GetPISnapshotData\"\n\n";
                                                  request += "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
                                                  request += "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:pid=\"http://xml.osisoft.com/services/PIDataService\">\n";
                                                  request += "<soapenv:Header/>\n";
                                                  request += "<soapenv:Body>\n";
                                                  request += "<pid:GetPISnapshotData>\n";
                                                  request += "<pid:paths>\n";
                                                  request += "<pid:string>pi:\\\\PIServer\\sinusoid</pid:string>\n";
                                                  request += "</pid:paths>\n";
                                                  request += "</pid:GetPISnapshotData>\n";
                                                  request += "</soap:Body>\n";
                                                  request += "</soap:Envelope>\n\n";
                                                  try
                                                  {
                                                      String html = Post(httpserver, httpport, request);
                                                      Debug.Print(html);
                                                  }
                                                  catch (SocketException se)
                                                  {
                                                      Debug.Print("SocketException when connecting to " + httpserver + ":" + httpport);
                                                      Debug.Print("If your network uses IPSec, you may need enable the port manually");
                                                      Debug.Print("Socket Error Code: " + se.ErrorCode.ToString());
                                                      Debug.Print(se.ToString());
                                                  }
                                              }
                                      
                                              /// <summary>
                                              /// Issues a http POST request on the specified server.
                                              /// </summary>
                                              /// <param name="server"></param>
                                              /// <param name="port"></param>
                                              /// <param name="request"></param>
                                              /// <returns></returns>
                                              private static String Post(String server, Int32 port, String request)
                                              {
                                                  const Int32 c_microsecondsPerSecond = 1000000;
                                      
                                                  // Create a socket connection to the specified server and port.
                                                  using (Socket serverSocket = ConnectSocket(server, port))
                                                  {
                                                      // Send request to the server.
                                                      Byte[] bytesToSend = Encoding.UTF8.GetBytes(request);
                                                      serverSocket.Send(bytesToSend, bytesToSend.Length, 0);
                                      
                                                      // Reusable buffer for receiving chunks of the document.
                                                      Byte[] buffer = new Byte[1024];
                                      
                                                      // Accumulates the received page as it is built from the buffer.
                                                      String page = String.Empty;
                                      
                                                      // Wait up to 30 seconds for initial data to be available.  Throws an exception if the connection is closed with no data sent.
                                                      DateTime timeoutAt = DateTime.Now.AddSeconds(30);
                                                      while (serverSocket.Available == 0 && DateTime.Now < timeoutAt)
                                                      {
                                                          System.Threading.Thread.Sleep(100);
                                                      }
                                      
                                                      // Poll for data until 30-second timeout.  Returns true for data and connection closed.
                                                      while (serverSocket.Poll(30 * c_microsecondsPerSecond, SelectMode.SelectRead))
                                                      {
                                                          try
                                                          {
                                                              // If there are 0 bytes in the buffer, then the connection is closed, or we have timed out.
                                                              if (serverSocket.Available == 0) break;
                                      
                                                              // Zero all bytes in the re-usable buffer.
                                                              Array.Clear(buffer, 0, buffer.Length);
                                      
                                                              // Read a buffer-sized HTML chunk.
                                                              Int32 bytesRead = serverSocket.Receive(buffer);
                                      
                                                              // Append the chunk to the string.
                                                              page = page + new String(Encoding.UTF8.GetChars(buffer));
                                                          }
                                                          catch (Exception Ex)
                                                          { 
                                                             Debug.Print(Ex.ToString());
                                                          }
                                                      }
                                                      // Return the complete string.
                                                      return page;
                                                  }
                                              }
                                      
                                              /// <summary>  
                                              /// Creates a socket and uses the socket to connect to the server's IP address and port.
                                              /// </summary>
                                              /// <param name="server"></param>
                                              /// <param name="port"></param>
                                              /// <returns></returns>
                                              private static Socket ConnectSocket(String server, Int32 port)
                                              {
                                                  // Get server's IP address.
                                                  IPHostEntry hostEntry = Dns.GetHostEntry(server);
                                      
                                                  // Create socket and connect to the server's IP address and port
                                                  Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                                  socket.Connect(new IPEndPoint(hostEntry.AddressList[0], port));
                                                  return socket;
                                              }
                                          }
                                      
                                      HTTP/1.1 404 Not Found
                                      Content-Type: text/html
                                      Server: Microsoft-IIS/8.0
                                      X-Powered-By: ASP.NET
                                      Date: Wed, 10 Jul 2013 18:25:20 GMT
                                      Content-Length: 1245
                                      
                                      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
                                      <html xmlns="http://www.w3.org/1999/xhtml">
                                      <head>
                                      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
                                      <title>404 - File or directory not found.</title>
                                      <style type="text/css">
                                      <!--
                                      body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
                                      fieldset{padding:0 15px 10px 15px;} 
                                      h1{font-size:2.4em;margin:0;color:#FFF;}
                                      h2{font-size:1.7em;margin:0;color:#CC0000;} 
                                      h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} 
                                      #header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
                                      background-color:#555555;}
                                      #content{margin:0 0 0 2%;position:relative;}
                                      .content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
                                      -->
                                      </style>
                                      </head>
                                      <body>
                                      <div id="header"><h1>Server Error</h1></div>
                                      <div id="content">
                                       <div class="content-container"><fieldset>
                                        <h2>404 - File or directory not found.</h2>
                                        <h3>The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable.</h3>
                                       </fieldset></div>
                                      </div>
                                      </body>
                                      </html>
                                      

                                       Any ideas or examples on how to do this?

                                        • Re: Arduino
                                          matthew.rivett

                                          The 404 error was indeed a 404 error.  I didn't have the correct path.

                                           
                                          String request = "POST http://" + httpserver + ":" + httpport + "/PIWebServices/PITimeSeries.svc HTTP/1.1\n";
                                          

                                           Now my request appears to be timing out.

                                            • Re: Arduino
                                              Lonnie Bowling

                                              Nice job Matt! So you are writing data now?  SOAP post and request can be hard to get right.  I'm really looking forward to the REST API stuff to come out, this will be much easier!

                                               

                                              Lonnie

                                                • Re: Arduino
                                                  matthew.rivett

                                                  No.  Right now I'm just trying to get the snapshot value for sinusoid.  It is timing out now; I'm no longer getting any errors.  This is all the IIS log shows and there's nothing in the PI logs.

                                                   

                                                  5488.iislog.JPG

                                                    • Re: Arduino
                                                      Lonnie Bowling

                                                      Hmm, have you heard of fiddler2?  It is an application that can show what is happening on the HTML stack.  I'm not sure if you could run it on the server side, but that would help figure out what is going on.  It will show you the post/response and can help a lot with these type of problems.  I'm not familiar with Arduino, but maybe you could use fiddler or even wireshark to help understand what is happening.

                                                        • Re: Arduino
                                                          Asle Frantzen

                                                          I'd like to take the time to recommend www.phidgets.com as an alternative to Arduino.

                                                           

                                                          I've used that both professionally and at home since 2003, and there are programming interfaces for a lot of languages available. Most of their stuff are USB-based and need a computer attached, but the SBC (single board computer) is a Debian-based stand alone thing with 8 analog, 8 digital inputs and 8 digital outputs. (For the SBC you can use only Java or C++)

                                                           

                                                          Here's a video from my first test of my latest creation, which is a control unit for turning the targets at my local shooting club:

                                                           

                                                          www.youtube.com/watch

                                                            • Re: Arduino
                                                              matthew.rivett

                                                              Lonnie: I'll have to look into fiddler2.

                                                               

                                                              Asle: I've been working with the Netduino.  I'm more comfortable with C# than the sketches used by the Arduino.  If I can't make it work I'll check out phidgets and see if it can be used.

                                                                • Re: Arduino
                                                                  Asle Frantzen

                                                                  I'll check that out. I'm also more comfortable with C#, and if I could find a cheap, stand-alone solution which allows for .net programming I'll probably dive into that.

                                                                  • Re: Arduino
                                                                    mhamel

                                                                    @Matt: If you want to use PI Web Services with message directly sent on the web socket, I invite to take a look at my past blog entry here. I am showing how to do it with PowerShell but this is farely the same.

                                                                     

                                                                    The XML message to send would be similar to this one:

                                                                     

                                                                     

                                                                     
                                                                    <?xml verstion="1.0" encoding="utf-8"?>
                                                                    <soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:pid=http://xml.osisoft.com/services/PIDataService>
                                                                         <soapenv:Header />
                                                                         <soapenv:Body>
                                                                              <pid:InsertPIData>
                                                                                <pid:MethodParameters>
                                                                                   <pid:events attr0="TimeSeriesArray" isNull="false">
                                                                                     <pid:TimeSeriesArray0 actualtype="TimeSeries" basetype="TimeSeries">
                                                                                        <pid:TimedValues attr0="TimedValueArray" isNull="false">
                                                                                          <pid:TimedValueArray0 actualtype="TimedValue" basetype="TimedValue">
                                                                                             <pid:Path>pi:\\core-tex\sinusoid</pid:Path>
                                                                                             <pid:Flags isNull="true" />
                                                                                             <pid:Time>7/11/2013 12:00:00 AM</pid:Time>
                                                                                             <pid:UOM isNull="true" />
                                                                                             <pid:Status>0</pid:Status>
                                                                                             <pid:PctGood>0</pid:PctGood>
                                                                                             <pid:PctGoodSpecified>False</pid:PctGoodSpecified>            
                                                                                             <pid:DataType>float</pid:DataType>
                                                                                             <pid:Value>2.0</pid:Value>
                                                                                          </pid:TimedValueArray0>
                                                                                        </pid:TimedValues>
                                                                                        <pid:Path isNull="true" />
                                                                                        <pid:ErrDesc isNull="true" />
                                                                                        <pid:Error>0</pid:Error>
                                                                                        <pid:SeriesID isNull="false" />
                                                                                        <pid:DataType>float</pid:DataType>
                                                                                        <pid:UOM isNull="true" />
                                                                                     </pid:TimeSeriesArray0>
                                                                                   </pid:events>
                                                                                   <pid:duplicateSwitch>InsertDuplicate</pid:duplicateSwitch>
                                                                                </pid:MethodParameters>
                                                                              </pid:InsertPIData>
                                                                         </soapenv:Body>          
                                                                    </soapenv:Envelope>
                                                                    

                                                                     

                                                                     

                                                                    I am wondering why you are not using a WebClient class directly. This would be easier.

                                                                      • Re: Arduino
                                                                        matthew.rivett

                                                                        Mathieu: The microprocessor is limited to the micro framework which does not have WebClient.  Thanks to the link to your powershell scripts.  I'll dig through them for some more ideas.

                                                                          • Re: Arduino
                                                                            matthew.rivett

                                                                            I'm trying the following post

                                                                             
                                                                                        String request = "POST http://" + httpserver + ":" + httpport + "/PIWebServices/PITimeSeries.svc HTTP/1.1\n";
                                                                                        request += "Host: " + httpserver + "\n";
                                                                                        request += "Content-Type: text/xml; charset=utf-8\n";
                                                                                        //request += "Content-Type: application/soap+xml; charset=utf-8\n";
                                                                                        request += "Content-Length: 418\n";
                                                                                        request += "SOAPAction: \"http://xml.osisoft.com/services/IPITimeSeries/GetPISnapshotData\"\n\n";
                                                                                        request += "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
                                                                                        request += "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:pid=\"http://xml.osisoft.com/services/PIDataService\">";
                                                                                        request += "<soapenv:Header/>";
                                                                                        request += "<soapenv:Body>";
                                                                                        request += "<pid:GetPISnapshotData>";
                                                                                        request += "<pid:paths>";
                                                                                        request += "<pid:path>pi\\\\piserver\\sinusoid</pid:path>";
                                                                                        request += "</pid:paths>";
                                                                                        request += "</pid:GetPISnapshotData>";
                                                                                        request += "</soapenv:Body>";
                                                                                        request += "</soapenv:Envelope>";
                                                                            

                                                                            and getting these messages in httperr.log

                                                                             
                                                                            2013-07-12 02:27:36 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:28:08 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:28:47 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:29:18 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:30:54 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:31:28 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:33:04 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc - 1 Timer_EntityBody PIWSAppPool
                                                                            2013-07-12 02:33:27 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc - 1 Connection_Abandoned_By_ReqQueue PIWSAppPool
                                                                            2013-07-12 02:34:53 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:35:28 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:36:04 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:36:38 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:38:13 192.168.1.12 4099 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc - 1 Timer_EntityBody PIWSAppPool
                                                                            2013-07-12 02:40:18 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:40:53 192.168.1.12 4097 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:41:29 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:42:03 192.168.1.12 4098 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            2013-07-12 02:42:39 192.168.1.12 4099 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 BadRequest PIWSAppPool
                                                                            2013-07-12 02:43:13 192.168.1.12 4099 192.168.1.210 80 HTTP/1.1 POST /PIWebServices/PITimeSeries.svc 400 1 Connection_Dropped PIWSAppPool
                                                                            

                                                                            I must not have the request formatted properly.

                                                                        • Re: Arduino
                                                                          matthew.rivett

                                                                          So there might be an easier way to do this.  there is a library called DPWS that stands for "Devices Profile for Web Services".  There is even a utility to generate classes from a WSDL.  Unfortunately I'm getting errors when I run it.

                                                                           

                                                                          Log and non working classes attached.  Does anyone have any ideas?

                                                                            • Re: Arduino
                                                                              matthew.rivett

                                                                              So I have this code at least compiling.  I was missing some references and made some guesses where no data types were supplied.  Now I don't know how to make sense of all the classes that have been created.  Are these the same classes that would be generated for any other web service application? 

                                                                               
                                                                                              Ws.Services.Binding.WS2007HttpBinding wsBind = new Ws.Services.Binding.WS2007HttpBinding();
                                                                                              System.Uri endPoint = new System.Uri("192.168.1.210");
                                                                                              wsBind.Transport.EndpointAddress = endPoint;
                                                                              
                                                                                              IPITimeSeriesClientProxy IPTSCP = new IPITimeSeriesClientProxy(wsBind, null);
                                                                              
                                                                                              ArrayOfTimeSeries AOTS = new ArrayOfTimeSeries();
                                                                                              ArrayOfString Paths = new ArrayOfString();
                                                                                              GetPISnapshotData GPSD = new GetPISnapshotData();
                                                                                              GetPISnapshotDataResponse GPSDR = new GetPISnapshotDataResponse();
                                                                                              GPSD.paths = Paths;
                                                                              
                                                                                              Paths.STRING = "\\\\pi01awt\\sinusoid";
                                                                              
                                                                              
                                                                                              GPSDR = IPTSCP.GetPISnapshotData(GPSD);
                                                                              

                                                                               

                                                                               

                                                                               Right now I'm just trying to get the sinusoid snapshot value.  I haven't done much work with web services of any kind so I'm not very familiar with bindings and am sure I've probably made some mistakes there.