<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Raspberry Pi - Alexander Development]]></title><description><![CDATA[Raspberry Pi - Alexander Development]]></description><link>https://alexanderdevelopment.net/</link><image><url>https://alexanderdevelopment.net/favicon.png</url><title>Raspberry Pi - Alexander Development</title><link>https://alexanderdevelopment.net/</link></image><generator>Ghost 1.20</generator><lastBuildDate>Mon, 24 Aug 2020 19:54:26 GMT</lastBuildDate><atom:link href="https://alexanderdevelopment.net/tag/raspberry-pi/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[A motion-activated spider for Halloween with an Arduino and a Raspberry Pi]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Every year my family hangs a large decorative spider over our doorway for Halloween. This year I decided to make it flash red LED eyes and play a random assortment of spooky sounds (including, but not limited to, bats, chains and the Vincent Price laugh from &quot;Thriller&quot;) when</p></div>]]></description><link>https://alexanderdevelopment.net/post/2018/10/26/a-motion-activated-spider-for-halloween-with-an-arduino-and-a-raspberry-pi/</link><guid isPermaLink="false">5bd2522e14b5e0000112ec57</guid><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Arduino]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Fri, 26 Oct 2018 14:11:53 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2018/10/candy-corn.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2018/10/candy-corn.jpg" alt="A motion-activated spider for Halloween with an Arduino and a Raspberry Pi"><p>Every year my family hangs a large decorative spider over our doorway for Halloween. This year I decided to make it flash red LED eyes and play a random assortment of spooky sounds (including, but not limited to, bats, chains and the Vincent Price laugh from &quot;Thriller&quot;) when trick-or-treaters come to the door. In today's blog post, I'll show how I did it.</p>
<h4 id="theapproach">The approach</h4>
<p>A few years ago, I wrote a post about setting up a <a href="https://alexanderdevelopment.net/post/2016/01/18/dynamics-crm-and-the-internet-of-things-part-5/">motion-activated webcam to trigger license plate recognition with a Raspberry Pi</a>, so I already had a Raspberry Pi and an HC-SR04 ultrasonic rangefinder I could use to detect motion. I initially thought I would only need the Pi for this project, but as I started evaluating the physical constraints of my porch, I realized it would be difficult to mount the Pi in a secure location where it could handle motion detection and also flash the LED eyes. I decided a better approach would be to use an Arduino to detect motion and flash the LEDs, while the Pi would communicate with the Arduino over a serial connection and play Halloween sound effect MP3s.</p>
<h4 id="settingupthearduino">Setting up the Arduino</h4>
<p>I have two red LEDs taped over the spider's eyes that are connected in series to pin 12 on an Arduino UNO. The ultrasonic rangefinder is taped to the side of my porch so that trick-or-treaters have to pass by it before they can knock on my door, and it is connected to pin 9 for the trigger and pin 10 for the echo. The Arduino listens for serial commands from the Pi to measure distance or to flash the LEDs if the Pi determines the reported distance measurement means someone has approached.</p>
<p>Here's my sketch:</p>
<pre><code>//set the pin numbers
const int triggerPin = 9;
const int echoPin = 10;
const int ledPin = 12;

void setup() 
{
  Serial.begin(9600); // Starts the serial communication
  pinMode(triggerPin, OUTPUT); // Sets the triggerPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  pinMode(ledPin, OUTPUT);
}

void loop() 
{
  if (Serial.available() &gt; 0) { 
    int controlcode = Serial.parseInt();
    if(controlcode==1)
    {
      //clear the trigger pin
      digitalWrite(triggerPin, LOW);
      delayMicroseconds(2);

      //send a 10 microsecond pulse
      digitalWrite(triggerPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(triggerPin, LOW);

      //read the echo pin to get the duration in microseconds
      long duration = pulseIn(echoPin, HIGH);
      
      //calculate the distance in centimeters
      int distance = duration*0.034/2;
      
      //return the distance to the serial monitor
      Serial.println(distance);
    }
    if(controlcode==2)
    {
      flashEyes();
    }
  }
}

void flashEyes()
{
  //flash 50 times
  for(int i=0;i&lt;50;i++)
  {
    //turn the eyes on
    digitalWrite(ledPin, HIGH);
    
    //wait for 150ms
    delay(150);
    
    //turn the eyes off
    digitalWrite(ledPin, LOW);
    
    //wait for 100ms
    delay(100);
  }
}
</code></pre>
<h4 id="settinguptheraspberrypi">Setting up the Raspberry Pi</h4>
<p>My Raspberry Pi 2 Model B is connected to the Arduino over a standard USB A/B cable, and it's also connected to a Bluetooth speaker mounted behind the spider. To run things, I have a Python script that sends a serial command to the Arduino to measure the distance every 50 milliseconds. If the Arduino returns a value between 20 and 120 centimeters, the Python script sends a serial command to the Arduino to flash the LEDs, and uses <a href="https://linux.die.net/man/1/mpg123">mpg123</a> to play a random MP3 file.</p>
<p>Here's the script:</p>
<pre><code>import serial
import time
import subprocess
import random
port = &quot;/dev/ttyACM0&quot;

def playsound():
    i = 0
    screamnumber = str(random.randint(1,5))
    screamfile = &quot;/home/pi/halloween/X.mp3&quot;.replace(&quot;X&quot;,screamnumber) 
    subprocess.Popen([&quot;mpg123&quot;, screamfile])
 
if __name__ == '__main__':
    s1 = serial.Serial(
      port=port,\
      baudrate=9600)
    s1.flushInput()
    
    #wait 5 seconds before telling the arduino look for motion
    time.sleep(5)
    try:
        while True:
          if s1.in_waiting==0:
            #print('sent request')
            s1.write('1\n')
            time.sleep(.05)
          if s1.in_waiting&gt;0:
            #print('received response')
            inputValue = s1.readline()
            #print('Distance: ' + inputValue)
            if int(inputValue) &gt; 20 and int(inputValue) &lt; 120:
              print('Distance: ' + inputValue)
              s1.write('2\n')
              playsound()
              time.sleep(15)
            else:
              time.sleep(.05)
 
    #quit with ctrl + c
    except KeyboardInterrupt:
        print(&quot;script stopped by user&quot;)
</code></pre>
<p>To enable serial communication, I am using the <a href="https://github.com/pyserial/pyserial">pySerial</a> module. I should also note the logic for playing a random MP3 assumes that there are five files in the same directory as the script that are named 1.mp3, 2.mp3, etc. Using a different number of files would require changing the upper bound value on line 9.</p>
<p>Happy Halloween!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamics CRM and the Internet of Things - part 5]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This is the fifth and final post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM</p></div>]]></description><link>https://alexanderdevelopment.net/post/2016/01/18/dynamics-crm-and-the-internet-of-things-part-5/</link><guid isPermaLink="false">5a5837236636a30001b977fb</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Internet of Things]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 18 Jan 2016 22:17:57 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/12/streaming-interface-flow.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/12/streaming-interface-flow.png" alt="Dynamics CRM and the Internet of Things - part 5"><p>This is the fifth and final post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM + Internet of Things (IoT) integration. In my <a href="https://alexanderdevelopment.net/post/2016/01/12/dynamics-crm-and-the-internet-of-things-part-4/">previous post</a>, I showed how to execute the license plate recognition and contact search with JavaScript directly in the web resource. Today I will show how to set up a streaming interface so the Raspberry Pi can take a picture, parse the plate number and trigger the web resource to search for and display a contact without any input from the end user.</p>
<h4 id="theapproach">The approach</h4>
<p>As I described in <a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">part 1</a> of this series, in this approach the Raspberry Pi takes a picture, parses the plate number and writes it to a streaming interface using Socket.IO. A web page or client application picks up the plate numbers from that interface, and then it queries CRM for a contact with the returned license plate number to display the details to the user. Essentially this is just a variation on what I described in my <a href="https://alexanderdevelopment.net/post/2014/12/03/creating-a-near-real-time-streaming-interface-for-dynamics-crm-with-node-js-part-1/">&quot;Creating a near real-time streaming interface for Dynamics CRM with Node.js&quot;</a> series in late 2014.<br>
<img src="http://alexanderdevelopment.net/content/images/2015/12/streaming-interface-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 5"></p>
<h4 id="nodejscode">Node.js code</h4>
<p>In <a href="https://alexanderdevelopment.net/post/2015/12/21/dynamics-crm-and-the-internet-of-things-part-2/">part 2</a> I showed the complete Node.js code to support all the scenarios in this series, but I did not discuss the streaming interface. Basically the streaming interface behaves almost exactly the same as the non-streaming interface except instead of writing the JSON result object in the HTTP response, it posts the JSON result object to a Socket.IO interface.</p>
<pre><code>app.get('/check_plate_stream', function (req, res) {
	//generate a guid to use in the captured image file name
	var uuid1 = uuid.v1();
	
	//tell the webcam to take a picture and store it in the captures directory using the guid as the name
	exec('fswebcam -r 1280x720 --no-banner --quiet ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});
	
	//now that we have a picture saved, execute parse it with openalpr and return the results as json (the -j switch) 
	exec('alpr -j ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		//create a json object based on the alpr output
		var plateOutput = JSON.parse(stdout.toString());
		
		//add an "image" attribute to the alpr json that has a path to the captured image
		//this is so the client can view the license plage picture to verify alpr parsed it correctly
		plateOutput.image = '/captures/' + uuid1 + '.jpg';

		//write the json to the socket.io interface
		io.emit('message', plateOutput);

		//return a response to the caller that the message was sent
		res.send('message sent');

		//log the response from alpr
		console.log('alpr response: ' + stdout.toString());
		
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});
});
</code></pre>
<p>The triggering mechanism is still a web route, so it can be called in a number of different ways without having to modify the base code. I've written a separate Node.js application that uses an <a href="http://amzn.com/B00SXZWMCS">HC-SR04 ultrasonic rangefinder</a> to detect when a license plate moves into view and then call the streaming interface URL to trigger the license plate capture and recognition. The motion detection script is available on GitHub <a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/CrmLicensePlateRecognition/detectmotion.js">here</a>.</p>
<p>I am running the motion detection script on the same Raspberry Pi as the webcam, but it could easily be run on a separate piece of hardware, too. You could also use the same approach to connect it to any sort of other sensor or input.</p>
<p>Here is a picture of my motion detection rig with my unimpressed Great Dane behind it for scale.<br>
<img src="https://alexanderdevelopment.net/content/images/2016/01/20160118_154636.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 5"></p>
<h4 id="thewebresource">The web resource</h4>
<p>The web resource loads the Socket.IO library from a CDN.<br>
<code>&lt;script src=&quot;<a href="https://cdn.socket.io/socket.io-1.2.0.js">https://cdn.socket.io/socket.io-1.2.0.js</a>&quot;&gt;&lt;/script&gt;</code></p>
<p>The web resource then connects to the streaming interface and listens for a message. Once it picks up a license plate number from the streaming interface, it then queries CRM to find a contact just like in <a href="https://alexanderdevelopment.net/post/2016/01/12/dynamics-crm-and-the-internet-of-things-part-4/">part 4</a>.</p>
<pre><code>var piRootPath = "http://192.168.1.112:3000";
var socket = io("http://192.168.1.112:3000");

socket.on('message', function(resultObj){
$("#outputdiv").text("");
if(resultObj.results.length > 0) {
	var plateNum = resultObj.results[0].plate;
	var imgUrl = resultObj.image;
	$("#outputdiv").append("Detected plate number: " + plateNum + "<br>");
	
	$("#outputdiv").append("&lt;img src='" + piRootPath + imgUrl+ "' width='400' /&gt;");
	
	var oDataURI = Xrm.Page.context.getClientUrl()
	+ "/XRMServices/2011/OrganizationData.svc/"
	+ "ContactSet?$select=ContactId,FullName&$filter=lpa_Platenumber eq '" + plateNum +"'";
	
	var req = new XMLHttpRequest();
	req.open("GET", encodeURI(oDataURI), true);
	req.setRequestHeader("Accept", "application/json");
	//req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
	req.onreadystatechange = function () {
		if (this.readyState == 4 /* complete */) {
			req.onreadystatechange = null; //avoids memory leaks
			if (this.status == 200) {
				successCrmCallback(JSON.parse(this.responseText).d.results);
			}
			else {
				errorCallback();
			}
		}
	};
	req.send();
}
else {
	$("#outputdiv").append("No plate detected<br>");
}
});
</code></pre>
<p>If a matching contact is found, it's displayed. Otherwise a failure message is displayed instead.</p>
<pre><code>function successCrmCallback(contacts) {
	if(contacts.length > 0) {
		var contactUrl = Xrm.Page.context.getClientUrl() + "/main.aspx?etc=2&extraqs=&pagetype=entityrecord&id=%7b" + contacts[0].ContactId + "%7d";
		$("#outputdiv").prepend("Contact: &lt;a href='" + contactUrl + "' target='_blank'&gt;" + contacts[0].FullName + "&lt;/a&gt;&lt;br /&gt;");	
	}
	else {
		//otherwise display a message that no contact could be found
		$("#outputdiv").prepend("No contact found<br>");
	}
	$("#checkButton").prop('disabled', false);
}
</code></pre>
<p>The web resource (lpa_checkplatestream.htm) is included in my sample CRM solution along with the contact entity configured to store the license plate number. The sample CRM solution is available in my GitHub repository <a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/CrmLicensePlateRecognition/LicensePlateDemo_0_0_0_1.zip">here</a>.</p>
<h4 id="demo">Demo</h4>
<p>Here's the CRM web resource open a new tab. Note there's no button to trigger the plate capture and recognition.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/stream-web-resource-before.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 5"></p>
<p>This is the web page used to trigger the plate capture and recognition opened in Chrome.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/stream-trigger.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 5"> When using my motion detection script, this page is never shown to the end user.</p>
<p>Finally here is the web resource once it gets the message from the stream and looks up the contact details. If the plate recognition is triggered again, the page will update itself.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/stream-web-resource-after.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 5"></p>
<h4 id="wrappingup">Wrapping up</h4>
<p>I hope you've enjoyed reading this series as much as I've enjoyed writing it. Through the process of working out the various scenarios I've certainly learned a lot about how the Raspberry Pi can be combined with Dynamics CRM to support novel business processes.</p>
<p>Here are links to all the previous posts in this series.</p>
<ol>
<li><a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">Part 1</a> - Series introduction</li>
<li><a href="https://alexanderdevelopment.net/post/2015/12/21/dynamics-crm-and-the-internet-of-things-part-2/">Part 2</a> - Node.js application</li>
<li><a href="https://alexanderdevelopment.net/post/2016/01/03/dynamics-crm-and-the-internet-of-things-part-3/">Part 3</a> - CRM custom assembly trigger</li>
<li><a href="https://alexanderdevelopment.net/post/2016/01/11/dynamics-crm-and-the-internet-of-things-part-4/">Part 4</a> - JavaScript in CRM web resource trigger</li>
</ol>
<p>Do you have plans to integrate your Dynamics CRM system with the Internet of Things? If so, how? Let us know in the comments!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamics CRM and the Internet of Things - part 4]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This is the fourth post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM + Internet of</p></div>]]></description><link>https://alexanderdevelopment.net/post/2016/01/11/dynamics-crm-and-the-internet-of-things-part-4/</link><guid isPermaLink="false">5a5837236636a30001b977f6</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Internet of Things]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 11 Jan 2016 13:38:49 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow.png" alt="Dynamics CRM and the Internet of Things - part 4"><p>This is the fourth post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM + Internet of Things (IoT) integration. In my <a href="https://alexanderdevelopment.net/post/2016/01/03/dynamics-crm-and-the-internet-of-things-part-3/">previous post</a>, I showed how to trigger the license plate recognition process and then use the extracted license plate number to find a contact in my Dynamics CRM organization with a custom workflow activity. Today I'll show how to execute the license plate recognition and contact search with JavaScript directly in the web resource.</p>
<h4 id="theapproach">The approach</h4>
<p>As I described in <a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">part 1</a> of this series, this approach uses JavaScript to call the Raspberry Pi to take a picture and return the parsed license plate number. Once a license plate number is retrieved, the JavaScript code then queries CRM for a contact with the returned license plate number and displays its details to the user. As long as the CRM end user's computer can access the Raspberry Pi, it doesn't matter if the Pi is visible to the CRM server, so this easily works with CRM Online.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 4"></p>
<h4 id="thewebresource">The web resource</h4>
<p>A web resource is used so the user can interactively trigger the license plate recognition and open the contact record if a match is found. The web resource also displays the image that is captured by the Raspberry Pi so the user can validate that the license plate number extracted by OpenALPR matches the actual license plate number.</p>
<p>Executing the license plate recognition on the Raspberry Pi just requires making a GET request to the Node.js web page described in <a href="https://alexanderdevelopment.net/post/2015/12/21/dynamics-crm-and-the-internet-of-things-part-2/">part 2</a> and then parsing the JSON response.</p>
<pre><code>//command to start checklplate action call when button is pushed  
function executeCheckplate() { 
	$("#outputdiv").text("");
	$("#checkButton").prop('disabled', true);
	var checkplateURI = piRootPath + "/check_plate";
    var req = new XMLHttpRequest();
    req.open("GET", encodeURI(checkplateURI), true);
    req.setRequestHeader("Accept", "application/json");
    //req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.onreadystatechange = function () {
        //debugger;
        if (this.readyState == 4 /* complete */) {
            req.onreadystatechange = null; //avoids memory leaks
            if (this.status == 200) {
                successPlateCallback(JSON.parse(this.responseText));
            }
            else {
                errorCallback();
            }
        }
    };
    req.send();
}
</code></pre>
<p>Once the response is returned from the Raspberry Pi, the web resource then queries CRM to find a contact, unless no plate was detected, in which case it displays a failure message.</p>
<pre><code>function successPlateCallback(resultObj) {
	if(resultObj.results.length > 0) {
		var plateNum = resultObj.results[0].plate;
		var imgUrl = resultObj.image;
		$("#outputdiv").append("Detected plate number: " + plateNum + "<br>");
		
		//show the captured plate image
		$("#outputdiv").append("&lt;img src='" + piRootPath + imgUrl+ "' width='400' /&gt;");
		
		var oDataURI = Xrm.Page.context.getClientUrl()
        + "/XRMServices/2011/OrganizationData.svc/"
        + "ContactSet?$select=ContactId,FullName&$filter=lpa_Platenumber eq '" + plateNum +"'";
		
		var req = new XMLHttpRequest();
		req.open("GET", encodeURI(oDataURI), true);
		req.setRequestHeader("Accept", "application/json");
		//req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
		req.onreadystatechange = function () {
			if (this.readyState == 4 /* complete */) {
				req.onreadystatechange = null; //avoids memory leaks
				if (this.status == 200) {
					successCrmCallback(JSON.parse(this.responseText).d.results);
				}
				else {
					errorCallback();
				}
			}
		};
		req.send();
	}
	else {
		$("#outputdiv").append("No plate detected<br>");
		$("#checkButton").prop('disabled', false);
	}
}
</code></pre>
<p>If a matching contact is found, it's displayed. Otherwise a failure message is displayed instead.</p>
<pre><code>function successCrmCallback(contacts) {
	if(contacts.length > 0) {
		var contactUrl = Xrm.Page.context.getClientUrl() + "/main.aspx?etc=2&extraqs=&pagetype=entityrecord&id=%7b" + contacts[0].ContactId + "%7d";
		$("#outputdiv").prepend("Contact: <a href="https://alexanderdevelopment.net/post/2016/01/11/dynamics-crm-and-the-internet-of-things-part-4/" + contactUrl + "" target="_blank">" + contacts[0].FullName + "</a><br>");	
	}
	else {
		//otherwise display a message that no contact could be found
		$("#outputdiv").prepend("No contact found<br>");
	}
	$("#checkButton").prop('disabled', false);
}
</code></pre>
<p>The web resource (lpa_checkplatejs.htm) is included in my sample CRM solution along with the contact entity configured to store the license plate number. The sample CRM solution is available in my GitHub repository <a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/CrmLicensePlateRecognition/LicensePlateDemo_0_0_0_1.zip">here</a>.</p>
<h4 id="demo">Demo</h4>
<p>Here's the web resource open a new tab.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/js-web-resource-before.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 4"></p>
<p>Here's the result after I click the &quot;check plate&quot; button. The contact name is a hyperlink that will open the contact record in a new window.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/js-web-resource-after.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 4"></p>
<p>That's it for today. In my next and final post in this series, I'll show how to set up a streaming interface so the Raspberry Pi can take a picture and parse the plate number, which will then trigger the web resource to search for and display a contact without any input from the end user.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamics CRM and the Internet of Things - part 3]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This is the third post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM + Internet of</p></div>]]></description><link>https://alexanderdevelopment.net/post/2016/01/03/dynamics-crm-and-the-internet-of-things-part-3/</link><guid isPermaLink="false">5a5837236636a30001b977f1</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Internet of Things]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Sun, 03 Jan 2016 23:19:06 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/12/custom-assembly-flow-2.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/12/custom-assembly-flow-2.png" alt="Dynamics CRM and the Internet of Things - part 3"><p>This is the third post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although the code samples are focused on license plate recognition, the solution architecture I used is applicable to any Dynamics CRM + Internet of Things (IoT) integration. In my <a href="https://alexanderdevelopment.net/post/2015/12/21/dynamics-crm-and-the-internet-of-things-part-2/">previous post</a>, I showed how I set up my Raspberry Pi to capture images and parse them for license plate numbers. In today's post, I will show how to trigger the license plate recognition process and then use the extracted license plate number to find a contact in my Dynamics CRM organization with a custom workflow activity.</p>
<h4 id="theapproach">The approach</h4>
<p>As I described in <a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">part 1</a> of this series, this approach uses a web resource, a dialog or some other interactive mechanism to call a custom workflow activity that instructs the Raspberry Pi to take a picture and return the parsed license plate number. The code hosted in CRM then searches for a contact with the returned license plate number and displays its details to the user. This requires that the CRM server be able to communicate with the Raspberry Pi, which may be challenging for CRM Online deployments.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/custom-assembly-flow-1.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 3"></p>
<p>Today I'll show how to call the custom workflow activity from a web resource, which will require the use of a custom CRM action so that the web resource can execute the functionality with a JavaScript call.</p>
<h4 id="thecustomworkflowassembly">The custom workflow assembly</h4>
<p>Interacting with the Node.js web page just requires making a GET request and then parsing the JSON response, so the <a href="https://alexanderdevelopment.net/Postingprocessing-JSON-in-396ead03">approach to working with JSON data in custom workflow assemblies</a> that I've used in several other posts will work great for this.</p>
<p>There are only a few changes required to that sample:</p>
<ol>
<li>Modify the JSON response classes to match the JSON object returned by the Node.js application.</li>
<li>Modify the web request to be a GET instead of a POST.</li>
<li>Add logic to search for contacts by license plate number and return the contact id as a string.</li>
<li>Update the input/output parameters to return the contact, license plate and image details.</li>
</ol>
<p>The code for the custom workflow assembly is available in my Crm-Sample-Code repository on GitHub <a href="https://github.com/lucasalexander/Crm-Sample-Code/tree/master/CrmLicensePlateRecognition/LicensePlateDemo">here</a></p>
<p>One thing to keep in mind is that because I wanted to register the assembly in isolation, I had to create a hosts entry for my Raspberry Pi on my CRM application server since sandboxed assemblies cannot make web requests to IP address URLs. Alternatively I could have created an entry on my LAN DNS server.</p>
<h4 id="thecustomcrmaction">The custom CRM action</h4>
<p>A custom CRM action is used to wrap the workflow assembly so that it can be called from a web resource via JavaScript. The action simply passes a request to the workflow assembly and returns its response to the client.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/custom-action.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 3"></p>
<h4 id="thewebresource">The web resource</h4>
<p>Finally a web resource is used so the user can interactively trigger the license plate recognition and open the contact record if a match is found. The web resource also displays the image that is captured by the Raspberry Pi so the user can validate that the license plate number extracted by OpenALPR matches the actual license plate number.</p>
<p>The web resource (lpa_checkplate.htm) is included in my sample CRM solution along with the custom action, compiled plugin and contact entity configured to store the license plate number. The sample CRM solution is available in my GitHub repository <a href="https://github.com/lucasalexander/Crm-Sample-Code/blob/master/CrmLicensePlateRecognition/LicensePlateDemo_0_0_0_1.zip">here</a>.</p>
<h4 id="demo">Demo</h4>
<p>Here's the web resource open a new tab.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/web-resource-before-1.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 3"></p>
<p>Here's the result after I click the &quot;check plate&quot; button. The contact name is a hyperlink that will open the contact record in a new window.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/web-resource-after.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 3"></p>
<p>That's it for today. In my next post, I'll show how to execute the license plate recognition and contact search with JavaScript directly in the web resource.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamics CRM and the Internet of Things - part 2]]></title><description><![CDATA[<div class="kg-card-markdown"><p>This is the second post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. As I mentioned in the <a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">first post</a> of the series, the solution architecture I used is applicable to any Dynamics CRM + Internet of</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/12/21/dynamics-crm-and-the-internet-of-things-part-2/</link><guid isPermaLink="false">5a5837236636a30001b977ec</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Internet of Things]]></category><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 21 Dec 2015 16:50:02 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/12/node-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/12/node-1.png" alt="Dynamics CRM and the Internet of Things - part 2"><p>This is the second post in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. As I mentioned in the <a href="https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/">first post</a> of the series, the solution architecture I used is applicable to any Dynamics CRM + Internet of Things (IoT) integration. In today's post I will show how I set up my Raspberry Pi to handle the basic license plate capture and parsing operations.</p>
<h4 id="tooling">Tooling</h4>
<p>For this demonstration I am using the following tools:</p>
<ol>
<li><a href="https://www.raspberrypi.org/products/raspberry-pi-2-model-b/">Raspberry Pi 2 Model B</a> running <a href="https://www.raspberrypi.org/downloads/raspbian/">Raspbian</a> (Any Linux distribution that runs on the Raspberry Pi should work with the code I'm showing, but the configuration steps later might be different.)</li>
<li><a href="http://www.logitech.com/en-us/product/hd-webcam-c615">Logitech HD Webcam C615</a> to take photos</li>
<li><a href="http://www.openalpr.com/">OpenALPR</a> to recognize license plates</li>
<li><a href="https://nodejs.org">Node.js</a> to provide a web-based interface to OpenALPR (and post to <a href="http://socket.io/">Socket.IO</a> in the streaming interface)</li>
</ol>
<p>OpenALPR and Node.js both run on Windows, so I think it should be possible to create a comparable solution using <a href="https://www.raspberrypi.org/blog/windows-10-for-iot/">Windows 10 for IoT</a> on a Raspberry Pi 2. Also, if you don't have a Pi or comparable IoT device, you can try this out on any system where you can run the software.</p>
<h4 id="basicraspberrypiconfiguration">Basic Raspberry Pi configuration</h4>
<p>Configuring the Raspberry Pi is beyond the scope of today's post, but as long as you have a Raspberry Pi running Raspbian with network access you should be good to go. My Pi is on my LAN with an IP address of 192.168.1.112, and all ports are open.</p>
<h4 id="camera">Camera</h4>
<p>I am using a Logitech HD Webcam C615 because I just happened to have one available. Theoretically any Raspberry Pi-compatible webcam or the dedicated Raspberry Pi camera module should work. I am using the fswebcam package to interact with my webcam, and I followed the instructions <a href="https://www.raspberrypi.org/documentation/usage/webcams">here</a> to get it working. As you'll see from the captured image at the end of this post, the quality of the images I'm capturing leaves something to be desired, but things seem to be working well enough that I haven't explored different configuration options to improve the quality.</p>
<h4 id="openalpr">OpenALPR</h4>
<p>OpenALPR is the tool that parses images to find license plate numbers. You can download it from GitHub, and follow the directions in the &quot;Easy Way&quot; section <a href="https://github.com/openalpr/openalpr/wiki/Compilation-instructions-(Ubuntu-Linux)#the-easy-way">here</a> to build and install it. I also should be possible to use Docker as described <a href="https://github.com/openalpr/openalpr#docker">here</a>, but I haven't tried it myself.</p>
<p>Once you have OpenALPR installed, you can test that it's working using sample images like so:</p>
<pre>wget http://plates.openalpr.com/ea7the.jpg
alpr -c us ea7the.jpg

wget http://plates.openalpr.com/h786poj.jpg
alpr -c eu h786poj.jpg</pre>
<p>OpenALPR can also be run as a daemon that continually checks a camera stream and outputs detected license plates, but I chose not to use it in this case because the open source version never stops. If you put a license plate in front of the webcam, the open source OpenALPR daemon will just keep returning the parsed license plate number over and over again. I believe the commercial version includes a motion detector feature, but to put together this sample on the cheap, I didn't explore it.</p>
<h4 id="nodejs">Node.js</h4>
<p>Having put together a <a href="https://alexanderdevelopment.net/tag/node-js/">few proof-of-concept interfaces</a> using Node.js in the past, it was the first thing that came to mind to create a web-based interface to OpenALPR. You could use a variety of other options like Python, Perl, PHP or C# if you prefer, but Node.js made setting up this part of the sample extremely easy.</p>
<p>First you need to make sure Node.js is installed:</p>
<pre>sudo apt-get install nodejs</pre>
<p>Then you need to install the following modules with npm:</p>
<ol>
<li>node-uuid</li>
<li>express</li>
<li>socket.io</li>
</ol>
<h4 id="nodejscode">Node.js code</h4>
<p>Here is the complete Node.js code to support all the scenarios in this series:</p>
<pre><code>var http = require('http');
var express = require('express'),
    app = module.exports.app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server, {log:false, origins:'*:*'})
var uuid = require('node-uuid');
var sys = require('sys'),
    exec = require('child_process').exec;

//allow clients to directly view the images in the captures directory
app.use('/captures', express.static('captures'));

//route for the home page
app.get('/', function (req, res) {
	res.send('home page');
});

//route to handle a client calling node to check a plage
app.get('/check_plate', function (req, res) {
	//generate a guid to use in the captured image file name
	var uuid1 = uuid.v1();
	
	//tell the webcam to take a picture and store it in the captures directory using the guid as the name
	exec('fswebcam -r 1280x720 --no-banner --quiet ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});

	//now that we have a picture saved, execute parse it with openalpr and return the results as json (the -j switch) 
	exec('alpr -j ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		//create a json object based on the alpr output
		var plateOutput = JSON.parse(stdout.toString());
		
		//add an "image" attribute to the alpr json that has a path to the captured image
		//this is so the client can view the license plage picture to verify alpr parsed it correctly
		plateOutput.image = '/captures/' + uuid1 + '.jpg';
		
		//set some headers to deal with CORS
		res.header("Access-Control-Allow-Origin", "*");
		res.header("Access-Control-Allow-Headers", "X-Requested-With");
		
		//send the json back to the client
		res.json(plateOutput);
		
		//log the response from alpr
		console.log('alpr response: ' + stdout.toString());
		
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});
});

//route to handle a request for a license plate capture to be written to a socket.io interface
//basically the same as the non-streaming interface except the output gets written somewhere different
app.get('/check_plate_stream', function (req, res) {
	//generate a guid to use in the captured image file name
	var uuid1 = uuid.v1();
	
	//tell the webcam to take a picture and store it in the captures directory using the guid as the name
	exec('fswebcam -r 1280x720 --no-banner --quiet ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});
	
	//now that we have a picture saved, execute parse it with openalpr and return the results as json (the -j switch) 
	exec('alpr -j ./captures/' + uuid1 + '.jpg',
	  function (error, stdout, stderr) {
		//create a json object based on the alpr output
		var plateOutput = JSON.parse(stdout.toString());
		
		//add an "image" attribute to the alpr json that has a path to the captured image
		//this is so the client can view the license plage picture to verify alpr parsed it correctly
		plateOutput.image = '/captures/' + uuid1 + '.jpg';

		//write the json to the socket.io interface
		io.emit('message', plateOutput);

		//return a response to the caller that the message was sent
		res.send('message sent');

		//log the response from alpr
		console.log('alpr response: ' + stdout.toString());
		
		if (error !== null) {
		  //log any errors
		  console.log('exec error: ' + error);
		}
	});
});

//start the server listening on port 3000
server.listen(3000, function () {
	console.log('App listening');
});
</code></pre>
<p>If you look at the &quot;check_plate&quot; route starting at line 19, you can see the script does the following things:</p>
<ol>
<li>Generate a new GUID to use in the captured image name.</li>
<li>Take a picture with the webcam and save it to the &quot;captures&quot; directory.</li>
<li>Execute OpenALPR to parse the image and return the results in a JSON object.</li>
<li>Modify the JSON object to include the image path</li>
<li>Return the JSON object to the client.</li>
</ol>
<h4 id="tryingitout">Trying it out</h4>
<p>To try out the code, do the following:</p>
<ol>
<li>Save the Node.js script from above as app.js.</li>
<li>Upload it to a directory on your Pi.</li>
<li>Create a directory called &quot;captures&quot; under that directory.</li>
<li>Start the application using the following command: nodejs app.js.</li>
<li>Navigate to the URL for the Node.js application from a web browser.</li>
</ol>
<p>Here's a picture of my testing &quot;studio.&quot; The Pi and webcam are sitting on a TV tray in front of an old license plate propped up on a couch in my office.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/20151221_102014_resized-1.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 2"></p>
<p>When I call Node.js from my browser, this is what I see.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/web-page.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 2"></p>
<p>This is the JSON response formatted for easier reading.</p>
<pre><code>{
	"version":2,
	"data_type":"alpr_results",
	"epoch_time":1450713975002,
	"img_width":1280,
	"img_height":720,
	"processing_time_ms":2567.216553,
	"regions_of_interest":[],
	"results":[
	{
		"plate":"43C32Y3",
		"confidence":91.097946,
		"matches_template":0,
		"plate_index":0,
		"region":"",
		"region_confidence":0,
		"processing_time_ms":269.342682,
		"requested_topn":10,
		"coordinates":[
		{
			"x":414,
			"y":315
		},
		{
			"x":812,
			"y":319
		},
		{
			"x":812,
			"y":516
		},
		{
			"x":414,
			"y":511
		}],
		"candidates":[
		{
			"plate":"43C32Y3",
			"confidence":91.097946,
			"matches_template":0
		},
		{
			"plate":"43G32Y3",
			"confidence":81.515587,
			"matches_template":0
		},
		{
			"plate":"43C3ZY3",
			"confidence":81.408203,
			"matches_template":0
		},
		{
			"plate":"43C32YS",
			"confidence":80.856506,
			"matches_template":0
		},
		{
			"plate":"43C32Y",
			"confidence":79.70826,
			"matches_template":0
		},
		{
			"plate":"43G3ZY3",
			"confidence":71.825851,
			"matches_template":0
		},
		{
			"plate":"43G32YS",
			"confidence":71.274155,
			"matches_template":0
		},
		{
			"plate":"43C3ZYS",
			"confidence":71.166771,
			"matches_template":0
		},
		{
			"plate":"43G32Y",
			"confidence":70.1259,
			"matches_template":0
		},
		{
			"plate":"43C3ZY",
			"confidence":70.018524,
			"matches_template":0
		}]
	}],
	"image":"/captures/be8da820-a7fc-11e5-a63a-7bb250f23f1c.jpg"
}
</code></pre>
<p>Here is the Node.js output from the Raspberry Pi command line.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/node.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 2"></p>
<p>This is the actual image the webcam captured. The white balance is horrible, but the plate number is clear enough for OpenALPR to recognize.<br>
<img src="https://alexanderdevelopment.net/content/images/2015/12/be8da820-a7fc-11e5-a63a-7bb250f23f1c.jpg#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 2"></p>
<p>That's it for now. In my next post, I'll show how to trigger the license plate recognition functionality from a custom assembly in Dynamics CRM.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Dynamics CRM and the Internet of Things - part 1]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Today's post is the first in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although my solution is focused on the use of license plate numbers captured by a webcam, the solution architecture is applicable to any</p></div>]]></description><link>https://alexanderdevelopment.net/post/2015/12/14/dynamics-crm-and-the-internet-of-things-part-1/</link><guid isPermaLink="false">5a5837236636a30001b977e7</guid><category><![CDATA[Microsoft Dynamics CRM]]></category><category><![CDATA[Raspberry Pi]]></category><category><![CDATA[Internet of Things]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Lucas Alexander]]></dc:creator><pubDate>Mon, 14 Dec 2015 16:02:17 GMT</pubDate><media:content url="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow-1.png" alt="Dynamics CRM and the Internet of Things - part 1"><p>Today's post is the first in a five-part series on how I integrated a Raspberry Pi with Microsoft Dynamics CRM to recognize contacts using automobile license plates. Although my solution is focused on the use of license plate numbers captured by a webcam, the solution architecture is applicable to any Dynamics CRM + Internet of Things (IoT) integration. Over the course of this series, I will show how I configured my Raspberry Pi and how I built different integrations to use the license plate data in Dynamics CRM.</p>
<h4 id="background">Background</h4>
<p>Last year I was working on a Dynamics CRM project for one of the largest automakers in the world, and I got to thinking about whether it'd be possible to integrate license plate recognition with our CRM system. This would have given dealers a tool so that service advisers could immediately see customer details and service preferences as soon as a car drove into a service bay. My idea never went anywhere, and eventually I moved on to a different company, but I'd still think about it every once in a while.</p>
<p>Then I saw an <a href="http://arstechnica.com/business/2015/12/new-open-source-license-plate-reader-software-lets-you-make-your-own-hot-list/">article</a> last week about open-source license plate reader software called <a href="http://www.openalpr.com/">OpenALPR</a> that got me thinking about this again. Because I'd just gotten a Raspberry Pi 2, and I had an old webcam that was just gathering dust in my office, I finally had everything I needed to build a Dynamics CRM license plate reader integration.</p>
<h4 id="theapproach">The approach</h4>
<p>Thinking about this from the perspective of a CRM user who wants to be able to recognize a contact based on a license plate, there are a few obvious elements required:</p>
<ol>
<li>Camera to capture a license plate image</li>
<li>Software to parse the license plate number from image (OpenALPR)</li>
<li>Code to trigger the license plate number parsing and return results to a consumer</li>
<li>Field to store license plate numbers in CRM</li>
<li>Code to retrieve and display the CRM contact details</li>
</ol>
<p>The right way to put these together is less obvious because there are several possible approaches, but none are appropriate in all scenarios. For example, if the CRM user is going to trigger the license plate recognition in CRM, there are at least three potential approaches:</p>
<ol>
<li>CRM custom assembly - Using a web resource, a dialog or some other interactive mechanism, a custom workflow activity or plug-in is called that instructs the Raspberry Pi to take a picture and return the parsed license plate number. The code hosted in CRM then searches for a contact with the returned license plate number and displays its details to the user. This approach requires that the CRM server be able to communicate with the Raspberry Pi, which may be challenging for CRM Online deployments.<img src="https://alexanderdevelopment.net/content/images/2015/12/custom-assembly-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 1"></li>
<li>JavaScript in web resource - Using a web resource, JavaScript is called that instructs the Raspberry Pi to take a picture and return the parsed license plate number. Once a license plate number is retrieved, the JavaScript code then queries CRM for a contact with the returned license plate number and displays its details to the user. As long as the CRM end user's computer can access the Raspberry Pi, it doesn't matter if the Pi is visible to the CRM server, so this easily works with CRM Online.<img src="https://alexanderdevelopment.net/content/images/2015/12/javascript-web-resource-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 1"></li>
<li>Business logic on the Raspberry Pi - Using a web resource, JavaScript is called that instructs the Raspberry Pi to take a picture and parse the license plate number. Once a license plate number is retrieved, the Raspberry Pi then queries CRM for a contact with the returned license plate number and returns its details to the user. I don't love this approach because it requires extra effort to get the Pi to communicate with CRM, and I prefer to keep the Pi as &quot;dumb&quot; as possible.<img src="https://alexanderdevelopment.net/content/images/2015/12/raspberry-pi-business-logic-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 1"></li>
</ol>
<p>If the license plate recognition is triggered via camera motion detection, a physical button or a sensor without direct input from the CRM user, there are at least two potential approaches:</p>
<ol>
<li>Streaming interface - The Raspberry Pi takes a picture, parses the plate number and writes it to a streaming interface using Socket.IO or a similar mechanism. A web page or client application picks up the plate numbers from that interface, and then it queries CRM for a contact with the returned license plate number to display the details to the user. This approach is basically a variation on what I described in my <a href="https://alexanderdevelopment.net/post/2014/12/03/creating-a-near-real-time-streaming-interface-for-dynamics-crm-with-node-js-part-1/">&quot;Creating a near real-time streaming interface for Dynamics CRM with Node.js&quot; series</a> last year.<img src="https://alexanderdevelopment.net/content/images/2015/12/streaming-interface-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 1"></li>
<li>Back-end data post - The Raspberry Pi takes a picture, parses the plate number and posts it to CRM. The data can be posted directly to CRM or use a <a href="https://alexanderdevelopment.net/post/2015/01/12/using-rabbitmq-as-a-message-broker-in-dynamics-crm-data-interfaces-part-1/">message queue</a>. This approach is good if a CRM user doesn't need immediate access to the data.<img src="https://alexanderdevelopment.net/content/images/2015/12/backend-data-post-flow.png#img-thumbnail" alt="Dynamics CRM and the Internet of Things - part 1"></li>
</ol>
<p>In this series I will show how I built solutions that demonstrate three of the approaches above:</p>
<ol>
<li>CRM custom assembly</li>
<li>JavaScript in web resource</li>
<li>Streaming interface</li>
</ol>
<p>As for why I'm not showing the other approaches:</p>
<ol>
<li>I just don't think the business logic on the Raspberry Pi approach is useful here. I'm sure there are times it might make sense, but my hypothetical scenario here isn't one of them.</li>
<li>The back-end data post approach is almost the same as the streaming interface, except the Pi posts the data to CRM instead of Socket.IO.</li>
</ol>
<p>In my next post, I'll show how I set up my Raspberry Pi to handle the basic license plate capture and parsing operations. See you then!</p>
</div>]]></content:encoded></item></channel></rss>