Trybotics Logo

Smart Garage Model by Blynk and XOD

DESCRIPTION

Video

Intro

Greetings, people!

Smart house concepts are no longer a novelty, and smart devices take a significant part of our lives. It is mainly made possible by the Internet of Things (IoT) networks which connect various electronic devices. With the IoT, you can automate your house with the smart temperature and humidity controllers, or remotely control lights, kettle, or even vacuum cleaner. Based on the trend of popularity, each house will become smart soon.

Of course, a smart home can be bought. However, I think it is better to make it smart by yourself, isn’t it? Nowadays, there are many different applications which allow anyone unfamiliar with electronics or programming to implement their ideas. In my opinion, it’s easier to understand the details of the topic while doing everything from scratch. Besides, the result will be much more valuable.

It's time for me to figure out how it works. For this, I decided to create an automated garage and describe the process in this article. In a fact, I have no spare garage, so I decided to build a smart garage model from the toy building.

Those who are unfamiliar with programming can find this article very useful because I’ll tell how to make it work without writing a single line of code. Let me share the experience.

Workpiece

It’s a two-story building made of wood. The garage occupies the ground floor, and there is a workshop on the second floor. In front of the building, there are three garage gates. On the opposite side, the building has a lift to the workshop and two additional entrances. The blue door leads to the workshop from the roof of the garage. The workshop roof can be opened to access inside. All gates in the garage open up.

This toy has a lot of moving parts, and it is large and inexpensive. In my opinion, it is ideal to practice the process of a smart house model creation.

Idea

First of all, the garage needs to get a “brain” to be smart. I took Arduino because it is easy to start with.

With Arduino controller, I’m going to operate various electronic devices and components at the garage as well as process data from sensors.

If my garage will become smart, how do I communicate with it?There are many technologies that enable IoT. A communication can be wired, for example via Ethernet. Or it can be wireless. Wireless networks use different protocols with the different ranges of action. The examples are Wi-Fi,RFID (Radio-frequency identification), NFC (Near-field communication), Bluetooth and so on. I think that garages, unlike smart homes, don't usually have high-quality wireless Internet.

I chose Bluetooth. Using this protocol I can control the garage with my smartphone whenever I need it. It is quite practical cause the phone is almost always at hand.

For the garage management, I’ll use a mobile application at my smartphone.

Hardware

I purchased all the necessary electronic components in one place. Surely you can find analogs at your local stores.

I chose the Arduino Mega 2560 microcontroller. This board has lots of digital and analog ports, supports many interfaces and it is sufficiently efficient. If you are planning to repeat the experiment, you can use any other microcontroller and board you like.

To connect my smartphone to Arduino via Bluetooth I’m going to use BLE (Bluetooth Low Energy) wireless technology. iOS, Android, Windows Phone Mobile operating systems natively support Bluetooth Low Energy so the connection shouldn’t be a problem no matter what smartphone model you have. For Arduino, I use this BLE HM-10 module based on a CC4051 microchip.

For the connecting convenience, I’ll use some Arduino expansion boards and pads for modules.

Since I don’t use a real building, I don’t need real electronic devices, or light bulbs, or other 220V powered equipment. Let it be the next step after my automatization model. Therefore, I can use hobby electronic components: LEDs, servos, sensors, etc.

Installation

Let's feature the garage.

At first, I choose a place for the Arduino Mega board. Let it be on the ground floor inside of the garage. There is some open space around, so I can access the board ports to connect modules and components.

The BLE module takes its place on the wall backside of the garage, so I can monitor the LEDs on the board indicating the Bluetooth connection status.

Let’s add some movement to the garage. The obvious solution is the front gates opening automatization. I attached these gates to three FS90 servos using the PVC blocks. Then I mount servo arms to the gate frames., I will open and close the gates by setting the servo values.

As any real room, the garage and the workshop should have a light. For this, I place two bright LEDs on the opposite walls on the ground floor and one LED on the second floor.

Time to add some smart sensors. I decided to make a parking assistant for the central garage box. For this, I use a GP2Y0A41 range meter by SHARP with the measuring range from 4 to 30 cm. I fix it by studs at the end of the garage box a short distance from the floor.

Suppose that lots of valuable things are stored at the workshop. For their safety, a security system should be installed at the workshop. I use the infrared motion sensor that reacts on the movement of a warm object, such as a human body. This kind of alarm is almost like the real thing. I mount this sensor on the workshop window.

What else to add? I decided to add the stoplight in front of one garage box. Of course, ordinary people don’t mount them on their building. Suppose this garage box is a car wash or a tire service, and the stoplight notifies customers. The stoplight is made of ordinary green and red LED.

I reckon these functions are enough to begin to work with. When all modules and components are fixed to the toy garage, I can define Arduino ports and connect them using wires to the board. Before programming the controller, I create a remote control.

Blynk

As I wrote above, I decided to control the garage remotely using a mobile application. But, how it can be done?

If you are familiar with programming and creating mobile applications, it is a piece of cake. However, this task is almost impossible for regular smartphone users. For those who still want to create their applications, there are lots of ready-made solutions. Spending some time choosing a mobile software I found Blynk.

Blynk software specially designed for IoT projects and it is compatible with most popular microcomputers and microcontrollers, including Arduino. What is even better is that it doesn’t require programming skills. So I will also take advantage of this software and create my application.

Next, I describe the process of making my remote control application. The detailed information can be found in the official Blynk documentation.

Making Application

At first, download and install the Blynk application on your Android or iOS smartphone.

Create a new Blynk account and log in.

Create a new Blynk project after login. Input the name of your project. Chose the device and connection type and press the “Create Project” button. I named my application “smart-garage”. According to the hardware I use, the device and connection types for my project are Arduino Mega and BLE respectively.

Check your Email address after creating the project. You’ll be sent a unique 32 digit token for your application. This token is used to pair your application with the hardware. Just write it down somewhere not to forget.

When you open the created project, you can see an empty workspace. Various elements called “Widgets” are placed on this workspace. Look at the full list of widgets at the Widget Box by swiping the screen to the left.

Please note, placing the widget on the workspace you spend “Blynk energy”. This resource isn’t free, so it is better to think over what your application should look like before buying widgets.

Widgets have different functions and are divided into groups. A widget can serve as a controller and send data to your IoT device, for example, Button or Slider. Another widget receives data from the device and shows it on the smartphone screen, for example, Value Display or LED. Some widgets can notify a user using a variety of services Twitter, Email) or even be utilities (Bridge, BLE, Real-time clock).

When I came up with the app, I begin to add widgets. The first widget that I need is BLE. This widget is used to enable Bluetooth Low Energy support.

Next, I add widgets to control the lights in the garage and workshop. I want the workshop light to be controlled by the push of a button. So, I put a Button widget into the workspace.

Now I need to configure the Button settings. For each widget which sends or receives values, you should set up a PIN. Blynk can control Digital and Analog Pins on your hardware directly, but often it’s just not enough. In Blynk, there is a concept of a “virtual pin” to be used in complex projects or custom implementations. This is the pin type I use in my application for all widgets. You can choose the available virtual pin number in the widget options. Also, you can customize your widget, change its color, name, size, switch the operating mode or change range for input and output values.

I name my button workshop-light and choose V1 virtual pin. Also, I make it act as a switch and change its color. workshop-light button outputs either 0 or 1 depending on a state. These values are going to turn on and off the LED in my workshop.

The control for the workshop light is ready, and now it is time for the light in the garage. I addition to turning the garage light on and off, I want to control its brightness. The Slider widget helps me. This widget can output values in a set range, depending on a slider position. I put it into the workspace, name it garage-light, bind it to the V2 virtual pin and change other properties that I want. The Slider outputs values in the range from 0 to 255 by default.

Next, I add gate control. For three gates I need 3 more buttons. I name them gate 1, gate 2, and gate 3. Let the virtual pins for these widgets be V3, V4, and V5 correspondingly. Also, I change them into switches and name the on/off states of this buttons as closed and opened.

I need one more switch to control the stoplight. I attach the switch to the V6 virtual pin and name the on/off states Stop and Go.

By now, all placed widgets are used only to send values. For my security system and parking sensor, I need feedback from the smart garage.

I want the current distance to an obstacle to be displayed on my screen. For this, I’m going to use the Labeled Value widget. I add it to the Blynk workspace of my application and name it parking-assistant. As for the previous widgets, I set a virtual pin. For the parking-assistant it is V7. Also, I need to make some additional settings. At the Label you can set what part of value or text will be displayed continuously and what part will change. I want a Distance: prefix before the value, so I put the Distance: /pin/ value in the field. At the Refresh interval, you can set the time for a value to be updated. I set up this field to Push to update the distance value by a microcontroller signal instead of constantly asking it for a new value.

I want to set the proper distance to the obstacle for the oncoming car at the garage box. For example, if the distance is less than 5 cm, the transport must stop. To display whether the specified distance has been reached, I need an indication. For this, I add a LED widget. The widget will change the color depending on the current distance to the obstacle. I attach the LED widget to the V8 virtual pin.

Now I’m going to add a widget for my security system. To notice the application user I also use the Labeled Value widget. Let the static part of the text in this widget be Status: , and the dynamic part of the text be ALARM if a sensor has seen a warm object. If everything is quiet at the workshop and no alarm is needed, the status field will be empty. For the security system widget, I chose the V9 virtual pin. The Label value is Status: /pin/ and the Refresh interval value is Push.

The remote control application is done. Let’s put it aside for a while and program the microcontroller.

XOD

I didn’t write a single line of code to create the program for the controller. I used the XOD visual programming environment. Instead of writing code, here, special blocks called “Nodes” are used. More information can be found on the documentation page at the XOD web site.

To make Blynk compatible program, I still had to make the gabbapeople/blynk library to support blynk in XOD. But if you want to repeat the experiment you just need to add the library to your workspace and use the ready-made nodes. Also, you can find the prepared patch in the gabbapeople/blynk library.

Here are steps required to reproduce my program.

Making Program

Create a new project and name it. I named it the same as the smartphone application.

Add the init-ble-uart node from the gabbapeople/blynk library the onto the patch. This node is necessary for the HM-10 BLE module operation.

Fill in the AUTH value field. Do you remember the 32-digit token that came to your e-mail? The AUTH pin is the place for this token. Thus, XOD and Blynk can identify each other.

A pulse on the INIT pin initializes a BLE device. The RUN pin is used to synchronize the application with the microcontroller.

The init-ble-uart node outputs the BLNK custom type which is necessary for other Blynk nodes to exchange values with widgets.

Since the HM-10 BLE module communicates with the Arduino board via UART, the UART type value must be set to the similar input pin of the node.

Initialize the interface. Arduino Mega Board has 3 additional Hardware UART interfaces, so, it makes sense to use them. I connected the BLE module to the 18 and 19 Rx and Tx ports of the first hardware UART interface. Then, I put the uart-1 node from the xod/uart library and link it with the init-ble-uart node. You can use a hardware or software UART interface you want.

For the HM-10 BLE module, the BAUD rate is 9600. Link the DONE pin of your UART node with the INIT pin of the init-ble-uart node to initialize the BLE module when the UART interface is ready.

It is better to set the RUN pin value to Continuously in order not to accidentally disrupt the application synchronization.

For the BLNK pin, I decided to make a bus for the visual convenience of the subsequent nodes. It can be done by selecting the BLNK pin and pressing the B key on the keyboard.

Now, using the nodes, I’m going to describe each function of the smart-garage. The light control is the first function of my program. The light widgets in my smartphone app send values via Bluetooth, so the controller should read and process them.

To read data from the Blynk application use the read node from the gabbapeople/blynk library.

The BLNK pin of the read node expects the BLNK type value. Set VPIN to choose the virtual pin to read data from. This VPIN values refer to those virtual pins that are used for widgets in the application. Pulse on the READ pin triggers a new reading of data. The DATA pin outputs a String type value from the selected virtual pin.

Now, let’s create nodes to control the workshop light. For this, I put the read node onto the patch and link it with the init-ble-uart node using the existing BLNK bus. The workshop-light widget attached to the V1 virtual pin, so I put the 1 value to the VPIN. I set the READ pin value to Continuously.

I’ve got one LED at the workshop. Therefore, I put led node onto the patch and name it workshop-led. LED is connected to the 13 digital Arduino port, so I put the 13 value to the PORT pin of the led node.

The workshop-light widget outputs either 0 or 1 value, depending on the switch state. With this range of values, I can link the LUM pin of the led node with the DATA output of the read node directly. The only thing I have to do, it is to convert the value from the String to Number. For this, l use the parse-number node. This node can be found in the gabbapeople/uart-led-control library, so I should add it to my XOD workspace too.

Now, all I have to do is to link the read and led nodes through the parse-number. Here's a patch that I came up with.

Next, I continue with the garage light. The garage-light widget outputs values, so I need the read node again. The program for it is almost the same except for some details. The garage light is made by two LEDs instead of one, so I put an additional led node onto the patch. The garage-light slider widget at my remote control application tunes brightness and outputs a value in the range from 0 to 255. The led node, in its turn, inputs LUM values in a range from 0 to 1. To set up new ranges, I’ll use the map-clip node and put it between led and parse-number.

Garage LEDs are connected to the 11 and 12 Arduino pins. The VPIN value at the read node is 2 as it is relevant to the V2 virtual pin at the widget. Here is the second branch of the patch.

Next, let’s program servos on the gates. I’ve got three gates mechanized by three servos. Servos are connected to the 43, 45, and 47 digital Arduino Mega pins. I put three servo nodes from the xod/common-hardware library. They are controlled by three button widgets at the application, and I need to put three read nodes. For this widgets, the VPIN values at read nodes are 3, 4, 5.

A button widget outputs 0 or 1 value. The 0 to 1 range of a servo node means the 0 to 180 degree rotation. So, I use map-clip nodes and custom ranges to adjust the angles to make servos open and close gates properly.

Also, I want to update the servos if only a new value comes. For this, I add put three pulse-on-change nodes and link them with UPD pins. Look at new branches of the patch.

The last application widget that outputs values is stoplight. The program for it is pretty simple. Button push turns the green LED on, and the red LED off. Pressing the button widget again will change the state of the LEDs to the opposite. As previous, I need read and parse-number nodes, two led nodes for the red and green LED on my stoplight. I connect leds to the 6 and 7 Arduino pins and put relevant values to the PORT pin of the leds. The virtual pin for the stoplight widget is V6. To invert the signal from the button, I use the not node. Here is the stoplight branch of the program.

Now, I need to create a program for those widgets that input values from the controller and shows them at the smartphone screen. For this, the write node from the gabbapeople/blynk library is used.

A value at the VPIN targets an application widget to write DATA. A pulse on a PUSH pin triggers a new DATA send.

Let’s make a parking assistant program. In the xod/common-hardware library there is a gp2y0a41-range-meter node for the sensor I use. The sensor is connected to the A8 analog Arduino pin. gp2y0a41-range-meter node outputs the distance value in meters, but I want to display it in centimeters. I multiply the sensor output by 100. Then, I forward the multiplied value to the DATA pin of the write node.

For the stable operation of the application, it is not recommended to send values too often. I limit the frequency of sending by attaching the clock node to the PUSH pin of the write. I want the write to push values to the application 4 times a second, and put the 0.25 second value the IVAL pin of the clock.

The labeled value widget at my application is attached to the V7 virtual pin, so I put the 7 value to the VPIN of the write node. Now, That’s the patch I have.

The Parking assistant consists of two widgets. The first one is a labeled field widget, and I described it. The second is the distance LED widget indicator. It is assumed that the indicator on the application screen changes its color depending on the current distance between the sensor and the obstacle. There is the widget-led node in the gabbapeople/blynk library for the LED application widget.

The widget-led node looks like the write, but it has some differences. It has the INIT that is used to initialize the widget On boot of the controller. Also, this node expects a CLR value instead of a DATA. A CLR pin value describes the color of the widget at the application. By changing this value, the widget can blink different colors. Possible CLR values and the format are the clearly defined:

  • BLYNK_GREEN value for the #23C48E color
  • BLYNK_BLUE value for the #04C0F8 color
  • BLYNK_YELLOW value for the #ED9D00 color
  • BLYNK_RED value for the #D3435C color
  • BLYNK_DARK_BLUE value for the #5F7CD8 color

I put the widget-led node onto the patch and make the condition using the if-else node. If the multiplied distance value is less than 6 cm the CLR is BLYNK_GREEN, otherwise it is BLYNK_RED.

The virtual pin for the LED widget at my application is V8, so I put the 8 value to the VPIN. You need to limit the sending frequency for this node too. I add the pulse-on-change node and link it with the PUSH pin to send a new color to the widget only when the target distance is reached. Look what the patch came out.

It remains only to program a security system. Security system widget is a labeled value, and I’m going to send a string values to the widget depending on the state of the motion sensor. I need the write node to push strings to the application and the if-else node to make a condition. The motion sensor that I have is digital. I can use the digital-read node. Sensor outputs 1 if there is motion in front of it and 0 if it is not.

I connected the sensor to the 38 digital Arduino port. The security system widget virtual pin value is V9. By the if-else node I check the state of the signal from the digital-read node. If the state is true or 1, I set the ALARM! value to the DATA pin, otherwise I set the line of spaces. Look at the security system branch of the patch.

The result is a large and interesting patch. Now I can upload it to my Arduino board.

Launch

By now, the BLE support in Blynk is in test mode. Therefore, you need to turn on the BLE widget transmitter manually in the application.

Open the Blynk application and push on the BLE widget. Next, you need to choose the BLE device that you have from the list. My HM-10 BLE module has the HM-soft name at the list. Then, press the connect button and ensure that a connection with the module has been established.

After it, you can launch your application by clicking on the arrow in the upper right corner.

Description:

Ardgen mega
Arduino Mega 2560 & Genuino Mega 2560
×1
Bluetooth Low Energy (BLE) Module (Generic)
×1

Description:

Description:

Video

Intro

Greetings, people!

Smart house concepts are no longer a novelty, and smart devices take a significant part of our lives. It is mainly made possible by the Internet of Things (IoT) networks which connect various electronic devices. With the IoT, you can automate your house with the smart temperature and humidity controllers, or remotely control lights, kettle, or even vacuum cleaner. Based on the trend of popularity, each house will become smart soon.

Of course, a smart home can be bought. However, I think it is better to make it smart by yourself, isn’t it? Nowadays, there are many different applications which allow anyone unfamiliar with electronics or programming to implement their ideas. In my opinion, it’s easier to understand the details of the topic while doing everything from scratch. Besides, the result will be much more valuable.

It's time for me to figure out how it works. For this, I decided to create an automated garage and describe the process in this article. In a fact, I have no spare garage, so I decided to build a smart garage model from the toy building.

Those who are unfamiliar with programming can find this article very useful because I’ll tell how to make it work without writing a single line of code. Let me share the experience.

Workpiece

It’s a two-story building made of wood. The garage occupies the ground floor, and there is a workshop on the second floor. In front of the building, there are three garage gates. On the opposite side, the building has a lift to the workshop and two additional entrances. The blue door leads to the workshop from the roof of the garage. The workshop roof can be opened to access inside. All gates in the garage open up.

This toy has a lot of moving parts, and it is large and inexpensive. In my opinion, it is ideal to practice the process of a smart house model creation.

Idea

First of all, the garage needs to get a “brain” to be smart. I took Arduino because it is easy to start with.

With Arduino controller, I’m going to operate various electronic devices and components at the garage as well as process data from sensors.

If my garage will become smart, how do I communicate with it?There are many technologies that enable IoT. A communication can be wired, for example via Ethernet. Or it can be wireless. Wireless networks use different protocols with the different ranges of action. The examples are Wi-Fi,RFID (Radio-frequency identification), NFC (Near-field communication), Bluetooth and so on. I think that garages, unlike smart homes, don't usually have high-quality wireless Internet.

I chose Bluetooth. Using this protocol I can control the garage with my smartphone whenever I need it. It is quite practical cause the phone is almost always at hand.

For the garage management, I’ll use a mobile application at my smartphone.

Hardware

I purchased all the necessary electronic components in one place. Surely you can find analogs at your local stores.

I chose the Arduino Mega 2560 microcontroller. This board has lots of digital and analog ports, supports many interfaces and it is sufficiently efficient. If you are planning to repeat the experiment, you can use any other microcontroller and board you like.

To connect my smartphone to Arduino via Bluetooth I’m going to use BLE (Bluetooth Low Energy) wireless technology. iOS, Android, Windows Phone Mobile operating systems natively support Bluetooth Low Energy so the connection shouldn’t be a problem no matter what smartphone model you have. For Arduino, I use this BLE HM-10 module based on a CC4051 microchip.

For the connecting convenience, I’ll use some Arduino expansion boards and pads for modules.

Since I don’t use a real building, I don’t need real electronic devices, or light bulbs, or other 220V powered equipment. Let it be the next step after my automatization model. Therefore, I can use hobby electronic components: LEDs, servos, sensors, etc.

Installation

Let's feature the garage.

At first, I choose a place for the Arduino Mega board. Let it be on the ground floor inside of the garage. There is some open space around, so I can access the board ports to connect modules and components.

The BLE module takes its place on the wall backside of the garage, so I can monitor the LEDs on the board indicating the Bluetooth connection status.

Let’s add some movement to the garage. The obvious solution is the front gates opening automatization. I attached these gates to three FS90 servos using the PVC blocks. Then I mount servo arms to the gate frames., I will open and close the gates by setting the servo values.

As any real room, the garage and the workshop should have a light. For this, I place two bright LEDs on the opposite walls on the ground floor and one LED on the second floor.

Time to add some smart sensors. I decided to make a parking assistant for the central garage box. For this, I use a GP2Y0A41 range meter by SHARP with the measuring range from 4 to 30 cm. I fix it by studs at the end of the garage box a short distance from the floor.

Suppose that lots of valuable things are stored at the workshop. For their safety, a security system should be installed at the workshop. I use the infrared motion sensor that reacts on the movement of a warm object, such as a human body. This kind of alarm is almost like the real thing. I mount this sensor on the workshop window.

What else to add? I decided to add the stoplight in front of one garage box. Of course, ordinary people don’t mount them on their building. Suppose this garage box is a car wash or a tire service, and the stoplight notifies customers. The stoplight is made of ordinary green and red LED.

I reckon these functions are enough to begin to work with. When all modules and components are fixed to the toy garage, I can define Arduino ports and connect them using wires to the board. Before programming the controller, I create a remote control.

Blynk

As I wrote above, I decided to control the garage remotely using a mobile application. But, how it can be done?

If you are familiar with programming and creating mobile applications, it is a piece of cake. However, this task is almost impossible for regular smartphone users. For those who still want to create their applications, there are lots of ready-made solutions. Spending some time choosing a mobile software I found Blynk.

Blynk software specially designed for IoT projects and it is compatible with most popular microcomputers and microcontrollers, including Arduino. What is even better is that it doesn’t require programming skills. So I will also take advantage of this software and create my application.

Next, I describe the process of making my remote control application. The detailed information can be found in the official Blynk documentation.

Making Application

At first, download and install the Blynk application on your Android or iOS smartphone.

Create a new Blynk account and log in.

Create a new Blynk project after login. Input the name of your project. Chose the device and connection type and press the “Create Project” button. I named my application “smart-garage”. According to the hardware I use, the device and connection types for my project are Arduino Mega and BLE respectively.

Check your Email address after creating the project. You’ll be sent a unique 32 digit token for your application. This token is used to pair your application with the hardware. Just write it down somewhere not to forget.

When you open the created project, you can see an empty workspace. Various elements called “Widgets” are placed on this workspace. Look at the full list of widgets at the Widget Box by swiping the screen to the left.

Please note, placing the widget on the workspace you spend “Blynk energy”. This resource isn’t free, so it is better to think over what your application should look like before buying widgets.

Widgets have different functions and are divided into groups. A widget can serve as a controller and send data to your IoT device, for example, Button or Slider. Another widget receives data from the device and shows it on the smartphone screen, for example, Value Display or LED. Some widgets can notify a user using a variety of services Twitter, Email) or even be utilities (Bridge, BLE, Real-time clock).

When I came up with the app, I begin to add widgets. The first widget that I need is BLE. This widget is used to enable Bluetooth Low Energy support.

Next, I add widgets to control the lights in the garage and workshop. I want the workshop light to be controlled by the push of a button. So, I put a Button widget into the workspace.

Now I need to configure the Button settings. For each widget which sends or receives values, you should set up a PIN. Blynk can control Digital and Analog Pins on your hardware directly, but often it’s just not enough. In Blynk, there is a concept of a “virtual pin” to be used in complex projects or custom implementations. This is the pin type I use in my application for all widgets. You can choose the available virtual pin number in the widget options. Also, you can customize your widget, change its color, name, size, switch the operating mode or change range for input and output values.

I name my button workshop-light and choose V1 virtual pin. Also, I make it act as a switch and change its color. workshop-light button outputs either 0 or 1 depending on a state. These values are going to turn on and off the LED in my workshop.

The control for the workshop light is ready, and now it is time for the light in the garage. I addition to turning the garage light on and off, I want to control its brightness. The Slider widget helps me. This widget can output values in a set range, depending on a slider position. I put it into the workspace, name it garage-light, bind it to the V2 virtual pin and change other properties that I want. The Slider outputs values in the range from 0 to 255 by default.

Next, I add gate control. For three gates I need 3 more buttons. I name them gate 1, gate 2, and gate 3. Let the virtual pins for these widgets be V3, V4, and V5 correspondingly. Also, I change them into switches and name the on/off states of this buttons as closed and opened.

I need one more switch to control the stoplight. I attach the switch to the V6 virtual pin and name the on/off states Stop and Go.

By now, all placed widgets are used only to send values. For my security system and parking sensor, I need feedback from the smart garage.

I want the current distance to an obstacle to be displayed on my screen. For this, I’m going to use the Labeled Value widget. I add it to the Blynk workspace of my application and name it parking-assistant. As for the previous widgets, I set a virtual pin. For the parking-assistant it is V7. Also, I need to make some additional settings. At the Label you can set what part of value or text will be displayed continuously and what part will change. I want a Distance: prefix before the value, so I put the Distance: /pin/ value in the field. At the Refresh interval, you can set the time for a value to be updated. I set up this field to Push to update the distance value by a microcontroller signal instead of constantly asking it for a new value.

I want to set the proper distance to the obstacle for the oncoming car at the garage box. For example, if the distance is less than 5 cm, the transport must stop. To display whether the specified distance has been reached, I need an indication. For this, I add a LED widget. The widget will change the color depending on the current distance to the obstacle. I attach the LED widget to the V8 virtual pin.

Now I’m going to add a widget for my security system. To notice the application user I also use the Labeled Value widget. Let the static part of the text in this widget be Status: , and the dynamic part of the text be ALARM if a sensor has seen a warm object. If everything is quiet at the workshop and no alarm is needed, the status field will be empty. For the security system widget, I chose the V9 virtual pin. The Label value is Status: /pin/ and the Refresh interval value is Push.

The remote control application is done. Let’s put it aside for a while and program the microcontroller.

XOD

I didn’t write a single line of code to create the program for the controller. I used the XOD visual programming environment. Instead of writing code, here, special blocks called “Nodes” are used. More information can be found on the documentation page at the XOD web site.

To make Blynk compatible program, I still had to make the gabbapeople/blynk library to support blynk in XOD. But if you want to repeat the experiment you just need to add the library to your workspace and use the ready-made nodes. Also, you can find the prepared patch in the gabbapeople/blynk library.

Here are steps required to reproduce my program.

Making Program

Create a new project and name it. I named it the same as the smartphone application.

Add the init-ble-uart node from the gabbapeople/blynk library the onto the patch. This node is necessary for the HM-10 BLE module operation.

Fill in the AUTH value field. Do you remember the 32-digit token that came to your e-mail? The AUTH pin is the place for this token. Thus, XOD and Blynk can identify each other.

A pulse on the INIT pin initializes a BLE device. The RUN pin is used to synchronize the application with the microcontroller.

The init-ble-uart node outputs the BLNK custom type which is necessary for other Blynk nodes to exchange values with widgets.

Since the HM-10 BLE module communicates with the Arduino board via UART, the UART type value must be set to the similar input pin of the node.

Initialize the interface. Arduino Mega Board has 3 additional Hardware UART interfaces, so, it makes sense to use them. I connected the BLE module to the 18 and 19 Rx and Tx ports of the first hardware UART interface. Then, I put the uart-1 node from the xod/uart library and link it with the init-ble-uart node. You can use a hardware or software UART interface you want.

For the HM-10 BLE module, the BAUD rate is 9600. Link the DONE pin of your UART node with the INIT pin of the init-ble-uart node to initialize the BLE module when the UART interface is ready.

It is better to set the RUN pin value to Continuously in order not to accidentally disrupt the application synchronization.

For the BLNK pin, I decided to make a bus for the visual convenience of the subsequent nodes. It can be done by selecting the BLNK pin and pressing the B key on the keyboard.

Now, using the nodes, I’m going to describe each function of the smart-garage. The light control is the first function of my program. The light widgets in my smartphone app send values via Bluetooth, so the controller should read and process them.

To read data from the Blynk application use the read node from the gabbapeople/blynk library.

The BLNK pin of the read node expects the BLNK type value. Set VPIN to choose the virtual pin to read data from. This VPIN values refer to those virtual pins that are used for widgets in the application. Pulse on the READ pin triggers a new reading of data. The DATA pin outputs a String type value from the selected virtual pin.

Now, let’s create nodes to control the workshop light. For this, I put the read node onto the patch and link it with the init-ble-uart node using the existing BLNK bus. The workshop-light widget attached to the V1 virtual pin, so I put the 1 value to the VPIN. I set the READ pin value to Continuously.

I’ve got one LED at the workshop. Therefore, I put led node onto the patch and name it workshop-led. LED is connected to the 13 digital Arduino port, so I put the 13 value to the PORT pin of the led node.

The workshop-light widget outputs either 0 or 1 value, depending on the switch state. With this range of values, I can link the LUM pin of the led node with the DATA output of the read node directly. The only thing I have to do, it is to convert the value from the String to Number. For this, l use the parse-number node. This node can be found in the gabbapeople/uart-led-control library, so I should add it to my XOD workspace too.

Now, all I have to do is to link the read and led nodes through the parse-number. Here's a patch that I came up with.

Next, I continue with the garage light. The garage-light widget outputs values, so I need the read node again. The program for it is almost the same except for some details. The garage light is made by two LEDs instead of one, so I put an additional led node onto the patch. The garage-light slider widget at my remote control application tunes brightness and outputs a value in the range from 0 to 255. The led node, in its turn, inputs LUM values in a range from 0 to 1. To set up new ranges, I’ll use the map-clip node and put it between led and parse-number.

Garage LEDs are connected to the 11 and 12 Arduino pins. The VPIN value at the read node is 2 as it is relevant to the V2 virtual pin at the widget. Here is the second branch of the patch.

Next, let’s program servos on the gates. I’ve got three gates mechanized by three servos. Servos are connected to the 43, 45, and 47 digital Arduino Mega pins. I put three servo nodes from the xod/common-hardware library. They are controlled by three button widgets at the application, and I need to put three read nodes. For this widgets, the VPIN values at read nodes are 3, 4, 5.

A button widget outputs 0 or 1 value. The 0 to 1 range of a servo node means the 0 to 180 degree rotation. So, I use map-clip nodes and custom ranges to adjust the angles to make servos open and close gates properly.

Also, I want to update the servos if only a new value comes. For this, I add put three pulse-on-change nodes and link them with UPD pins. Look at new branches of the patch.

The last application widget that outputs values is stoplight. The program for it is pretty simple. Button push turns the green LED on, and the red LED off. Pressing the button widget again will change the state of the LEDs to the opposite. As previous, I need read and parse-number nodes, two led nodes for the red and green LED on my stoplight. I connect leds to the 6 and 7 Arduino pins and put relevant values to the PORT pin of the leds. The virtual pin for the stoplight widget is V6. To invert the signal from the button, I use the not node. Here is the stoplight branch of the program.

Now, I need to create a program for those widgets that input values from the controller and shows them at the smartphone screen. For this, the write node from the gabbapeople/blynk library is used.

A value at the VPIN targets an application widget to write DATA. A pulse on a PUSH pin triggers a new DATA send.

Let’s make a parking assistant program. In the xod/common-hardware library there is a gp2y0a41-range-meter node for the sensor I use. The sensor is connected to the A8 analog Arduino pin. gp2y0a41-range-meter node outputs the distance value in meters, but I want to display it in centimeters. I multiply the sensor output by 100. Then, I forward the multiplied value to the DATA pin of the write node.

For the stable operation of the application, it is not recommended to send values too often. I limit the frequency of sending by attaching the clock node to the PUSH pin of the write. I want the write to push values to the application 4 times a second, and put the 0.25 second value the IVAL pin of the clock.

The labeled value widget at my application is attached to the V7 virtual pin, so I put the 7 value to the VPIN of the write node. Now, That’s the patch I have.

The Parking assistant consists of two widgets. The first one is a labeled field widget, and I described it. The second is the distance LED widget indicator. It is assumed that the indicator on the application screen changes its color depending on the current distance between the sensor and the obstacle. There is the widget-led node in the gabbapeople/blynk library for the LED application widget.

The widget-led node looks like the write, but it has some differences. It has the INIT that is used to initialize the widget On boot of the controller. Also, this node expects a CLR value instead of a DATA. A CLR pin value describes the color of the widget at the application. By changing this value, the widget can blink different colors. Possible CLR values and the format are the clearly defined:

  • BLYNK_GREEN value for the #23C48E color
  • BLYNK_BLUE value for the #04C0F8 color
  • BLYNK_YELLOW value for the #ED9D00 color
  • BLYNK_RED value for the #D3435C color
  • BLYNK_DARK_BLUE value for the #5F7CD8 color

I put the widget-led node onto the patch and make the condition using the if-else node. If the multiplied distance value is less than 6 cm the CLR is BLYNK_GREEN, otherwise it is BLYNK_RED.

The virtual pin for the LED widget at my application is V8, so I put the 8 value to the VPIN. You need to limit the sending frequency for this node too. I add the pulse-on-change node and link it with the PUSH pin to send a new color to the widget only when the target distance is reached. Look what the patch came out.

It remains only to program a security system. Security system widget is a labeled value, and I’m going to send a string values to the widget depending on the state of the motion sensor. I need the write node to push strings to the application and the if-else node to make a condition. The motion sensor that I have is digital. I can use the digital-read node. Sensor outputs 1 if there is motion in front of it and 0 if it is not.

I connected the sensor to the 38 digital Arduino port. The security system widget virtual pin value is V9. By the if-else node I check the state of the signal from the digital-read node. If the state is true or 1, I set the ALARM! value to the DATA pin, otherwise I set the line of spaces. Look at the security system branch of the patch.

The result is a large and interesting patch. Now I can upload it to my Arduino board.

Launch

By now, the BLE support in Blynk is in test mode. Therefore, you need to turn on the BLE widget transmitter manually in the application.

Open the Blynk application and push on the BLE widget. Next, you need to choose the BLE device that you have from the list. My HM-10 BLE module has the HM-soft name at the list. Then, press the connect button and ensure that a connection with the module has been established.

After it, you can launch your application by clicking on the arrow in the upper right corner.

Description:

blynk.xodballJSON
a xodball file
{
  "name": "blynk",
  "patches": {
    "@/1": {
      "links": {
        "rJOiShVcQ": {
          "id": "rJOiShVcQ",
          "input": {
            "nodeId": "r1msrhEcX",
            "pinKey": "HkXK-dGob"
          },
          "output": {
            "nodeId": "H1VcwdQqX",
            "pinKey": "B1gI0urv1W"
          }
        }
      },
      "nodes": {
        "H1VcwdQqX": {
          "boundLiterals": {
            "B143qAq1Q": "D2"
          },
          "id": "H1VcwdQqX",
          "position": {
            "x": 136,
            "y": 0
          },
          "type": "xod/gpio/digital-read"
        },
        "r1msrhEcX": {
          "id": "r1msrhEcX",
          "position": {
            "x": 136,
            "y": 102
          },
          "size": {
            "height": 51,
            "width": 374
          },
          "type": "xod/core/watch"
        }
      },
      "path": "@/1"
    },
    "@/11111": {
      "links": {
        "H1qCpUiq7": {
          "id": "H1qCpUiq7",
          "input": {
            "nodeId": "HJ8apUscQ",
            "pinKey": "H1Li3Ovtm"
          },
          "output": {
            "nodeId": "ry8AaLsqQ",
            "pinKey": "BkmeFD8OQ"
          }
        },
        "SytATUsqX": {
          "id": "SytATUsqX",
          "input": {
            "nodeId": "HJ8apUscQ",
            "pinKey": "rk65hdPYX"
          },
          "output": {
            "nodeId": "ry8AaLsqQ",
            "pinKey": "Sk450OL-X"
          }
        },
        "rke-1CIicX": {
          "id": "rke-1CIicX",
          "input": {
            "nodeId": "HkZy0Li9Q",
            "pinKey": "__in__"
          },
          "output": {
            "nodeId": "HJ8apUscQ",
            "pinKey": "H1BnItotm"
          }
        }
      },
      "nodes": {
        "HJ8apUscQ": {
          "boundLiterals": {
            "BJ5kfIqY7": "Continuously",
            "H1Li3Ovtm": "On Boot",
            "Skfea_wKX": "\"820adad2351840c88e91de8cd3bfec4e\""
          },
          "id": "HJ8apUscQ",
          "position": {
            "x": 102,
            "y": 204
          },
          "type": "@/init-ble-uart"
        },
        "HkZy0Li9Q": {
          "id": "HkZy0Li9Q",
          "label": "BLNK",
          "position": {
            "x": 102,
            "y": 306
          },
          "type": "xod/patch-nodes/to-bus"
        },
        "ry8AaLsqQ": {
          "boundLiterals": {
            "BytfJKIWX": "9600"
          },
          "id": "ry8AaLsqQ",
          "position": {
            "x": 102,
            "y": 102
          },
          "type": "xod/uart/uart-1"
        }
      },
      "path": "@/11111"
    },
    "@/blynk": {
      "attachments": [
        {
          "content": "\nstruct State {\n};\n\n{{#global}}\nclass BlynkStream;\n//class BlynkTimer;\n{{/global}}\n\nstruct Type {\n    uint8_t vpin;\n    char* vpinData;\n    BlynkStream* xodBlynk;\n   // BlynkTimer* xodTimer;\n};\n\n{{ GENERATED_CODE }}\n\nvoid evaluate(Context ctx) {\n}\n",
          "encoding": "utf-8",
          "filename": "patch.cpp"
        }
      ],
      "nodes": {
        "Byw_8FsYm": {
          "id": "Byw_8FsYm",
          "position": {
            "x": 0,
            "y": 0
          },
          "type": "xod/patch-nodes/not-implemented-in-xod"
        },
        "HyPU8YoKQ": {
          "id": "HyPU8YoKQ",
          "label": "BLNK",
          "position": {
            "x": 0,
            "y": 102
          },
          "type": "xod/patch-nodes/output-self"
        }
      },
      "path": "@/blynk"
    },
    "@/init-ble-uart": {
      "attachments": [
        {
          "content": "#pragma XOD require \"https://github.com/blynkkk/blynk-library\"\n\n// clang-format off\n{{#global}}\n#define BLYNK_MSG_LIMIT      1500\n#include <BlynkSimpleSerialBLE.h>\n\nextern \"C\" {\n    struct BlynkReq;\n    struct BlynkParam;\n    void BlynkWidgetWriteDefault(BlynkReq __attribute__((__unused__)) &request, const BlynkParam __attribute__((__unused__)) &param);\n   // void BlynkWidgetReadDefault(BlynkReq __attribute__((__unused__)) &request);\n}\n\nnamespace xodBlynkBle {\n    uint8_t blynkPin;\n    char blynkPinData[24];\n}\n\nBLYNK_WRITE_DEFAULT() {\n   xodBlynkBle::blynkPin = request.pin;\n   strcpy(xodBlynkBle::blynkPinData,param.asStr());\n}\n\n\n{{/global}}\n// clang-format on\n\nstruct State {\n    char auth[33] = { 0 };\n    uint8_t mem[sizeof(BlynkStream)];\n    //uint8_t mem2[sizeof(BlynkTimer)];\n    BlynkStream* xodBlynk;\n    //BlynkTimer* xodTimer;\n};\n\n{{ GENERATED_CODE }}\n\nvoid evaluate(Context ctx) {\n    auto state = getState(ctx);\n    auto uart = getValue<input_UART>(ctx);\n\n    if (isInputDirty<input_INIT>(ctx)){\n\n        state->xodBlynk = new (state->mem) BlynkStream(_blynkTransport);\n        //state->xodTimer = new (state->mem2) BlynkTimer;\n\n        dump(getValue<input_AUTH>(ctx),state->auth);\n        state->xodBlynk->begin(*(uart->toStream()),state->auth);\n        if (state->xodBlynk->connect()){\n            emitValue<output_DONE>(ctx, 1);\n        } else {\n            emitValue<output_ERR>(ctx, 1);\n        }\n    }\n\n    if(isInputDirty<input_RUN>(ctx) ){\n        state->xodBlynk->run();\n        //state->xodTimer->run();\n\n    }\n\n    ValueType<output_BLNK>::T obj;\n    //obj = { xodBlynkBle::blynkPin, xodBlynkBle::blynkPinData, state->xodBlynk, state->xodTimer };\n        obj = { xodBlynkBle::blynkPin, xodBlynkBle::blynkPinData, state->xodBlynk };\n    //obj.vpin = xodBlynkBle::blynkPinRead;\n    //obj.vpinData = xodBlynkBle::blynkPinReadData;\n    //obj.xodBlynk = state->xodBlynk;\n    emitValue<output_BLNK>(ctx, obj);\n}\n\n",
          "encoding": "utf-8",
          "filename": "patch.cpp"
        }
      ],
      "nodes": {
        "B16R3OwY7": {
          "id": "B16R3OwY7",
          "position": {
            "x": 442,
            "y": 204
          },
          "type": "xod/patch-nodes/not-implemented-in-xod"
        },
        "BJ5kfIqY7": {
          "id": "BJ5kfIqY7",
          "label": "RUN",
          "position": {
            "x": 510,
            "y": 102
          },
          "type": "xod/patch-nodes/input-pulse"
        },
        "H1BnItotm": {
          "id": "H1BnItotm",
          "label": "BLNK",
          "position": {
            "x": 442,
            "y": 306
          },
          "type": "@/output-blynk"
        },
        "H1Li3Ovtm": {
          "id": "H1Li3Ovtm",
          "label": "INIT",
          "position": {
            "x": 544,
            "y": 102
          },
          "type": "xod/patch-nodes/input-pulse"
        },
        "Skfea_wKX": {
          "id": "Skfea_wKX",
          "label": "AUTH",
          "position": {
            "x": 476,
            "y": 102
          },
          "type": "xod/patch-nodes/input-string"
        },
        "SkxwzLqFX": {
          "id": "SkxwzLqFX",
          "label": "DONE",
          "position": {
            "x": 510,
            "y": 306
          },
          "type": "xod/patch-nodes/output-pulse"
        },
        "rJ9IGUqF7": {
          "id": "rJ9IGUqF7",
          "label": "ERR",
          "position": {
            "x": 476,
            "y": 306
          },
          "type": "xod/patch-nodes/output-pulse"
        },
        "rk65hdPYX": {
          "id": "rk65hdPYX",
          "label": "UART",
          "position": {
            "x": 442,
            "y": 102
          },
          "type": "xod/uart/input-uart"
        }
      },
      "path": "@/init-ble-uart"
    },
    "@/led2": {
      "attachments": [
        {
          "content": "struct State {\n   // char data[24];\n};\n\n{{ GENERATED_CODE }}\n\nvoid evaluate(Context ctx) {\n    auto state = getState(ctx);\n    auto _blynk = getValue<input_BLNK>(ctx);\n    uint8_t _vpin = getValue<input_VPIN>(ctx);\n\n    if (isInputDirty<input_INIT>(ctx)){\n        uint8_t _vpin = getValue<input_VPIN>(ctx);\n        _blynk.xodBlynk->virtualWrite(_vpin,255);\n    }\n\n\n    if (isInputDirty<input_PUSH>(ctx)){\n  //      dump(getValue<input_CLR>(ctx),state->data);\n //       state->xodBlynkLED->setColor(state->data);\n      //  _blynk.xodBlynk->setProperty(_vpin,\"color\",state->data);\n         _blynk.xodBlynk->setProperty(_vpin,\"color\",\"#23C48E\");\n    }\n}\n\n",
          "encoding": "utf-8",
          "filename": "patch.cpp"
        }
      ],
      "nodes": {
        "BJlxkTPXqm": {
          "id": "BJlxkTPXqm",
          "label": "PUSH",
          "position": {
            "x": 203,
            "y": 0
          },
          "type": "xod/patch-nodes/input-pulse"
        },
        "By-l1TDmcm": {
          "id": "By-l1TDmcm",
          "position": {
            "x": -1,
            "y": 102
          },
          "type": "xod/patch-nodes/not-implemented-in-xod"
        },
        "H1g1awX9X": {
          "id": "H1g1awX9X",
          "label": "VPIN",
          "position": {
            "x": 66,
            "y": -1
          },
          "type": "xod/patch-nodes/input-number"
        },
        "Sy4xkTvXqQ": {
          "id": "Sy4xkTvXqQ",
          "label": "BLNK",
          "position": {
            "x": -1,
            "y": 0
          },
          "type": "@/input-blynk"
        },
        "SyGeJ6wmcm": {
          "id": "SyGeJ6wmcm",
          "label": "CLR",
          "position": {
            "x": 135,
            "y": 0
          },
          "type": "xod/patch-nodes/input-string"
        },
        "rJmgypP79X": {
          "id": "rJmgypP79X",
          "label": "INIT",
          "position": {
            "x": 271,
            "y": 0
          },
          "type": "xod/patch-nodes/input-pulse"
        }
      },
      "path": "@/led2"
    },
    "@/main": {
      "comments": {
        "B1VyxvXqX": {
          "content": "First floor light",
          "id": "B1VyxvXqX",
          "position": {
            "x": 544,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 204
          }
        },
        "HJX7xvXqQ": {
          "content": "Stoplight",
          "id": "HJX7xvXqQ",
          "position": {
            "x": 782,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 204
          }
        },
        "Hk_OlPQ9Q": {
          "content": "Parktronic",
          "id": "Hk_OlPQ9Q",
          "position": {
            "x": 1734,
            "y": 1224
          },
          "size": {
            "height": 51,
            "width": 340
          }
        },
        "HkgLxDm5m": {
          "content": "Gate 3",
          "id": "HkgLxDm5m",
          "position": {
            "x": 1462,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 170
          }
        },
        "S1hRxkK75Q": {
          "content": "Security system",
          "id": "S1hRxkK75Q",
          "position": {
            "x": 2142,
            "y": 1224
          },
          "size": {
            "height": 51,
            "width": 306
          }
        },
        "S1vSeD75Q": {
          "content": "Gate 2",
          "id": "S1vSeD75Q",
          "position": {
            "x": 1258,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 170
          }
        },
        "r162kD7cm": {
          "content": "Second floor light",
          "id": "r162kD7cm",
          "position": {
            "x": 408,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 102
          }
        },
        "ry2EePQ5m": {
          "content": "Gate 1",
          "id": "ry2EePQ5m",
          "position": {
            "x": 1054,
            "y": 612
          },
          "size": {
            "height": 51,
            "width": 170
          }
        }
      },
      "links": {
        "B12Z62Ec7": {
          "id": "B12Z62Ec7",
          "input": {
            "nodeId": "rySkj3Nq7",
            "pinKey": "ByAbJsV5X"
          },
          "output": {
            "nodeId": "ryd-T3E9Q",
            "pinKey": "ByAIWR_UZ"
          }
        },
        "B1F9GTV57": {
          "id": "B1F9GTV57",
          "input": {
            "nodeId": "By2Kz6Eqm",
            "pinKey": "BkjI-COLb"
          },
          "output": {
            "nodeId": "rkGrbXIG9Q",
            "pinKey": "rJFmgJehW"
          }
        },
        "B1H5faNcQ": {
          "id": "B1H5faNcQ",
          "input": {
            "nodeId": "rkp3CpiY7",
            "pinKey": "SkrgGYLxQ"
          },
          "output": {
            "nodeId": "BJDKG6457",
            "pinKey": "ByAIWR_UZ"
          }
        },
        "B1PSXaVqQ": {
          "id": "B1PSXaVqQ",
          "input": {
            "nodeId": "rkMkojkcm",
            "pinKey": "r1sfQ_6fb"
          },
          "output": {
            "nodeId": "H1xSbXUz57",
            "pinKey": "rJFmgJehW"
          }
        },
        "B1v9MaE97": {
          "id": "B1v9MaE97",
          "input": {
            "nodeId": "BJDKG6457",
            "pinKey": "BkjI-COLb"
          },
          "output": {
            "nodeId": "r1VBbX8z97",
            "pinKey": "rJFmgJehW"
          }
        },
        "BJqJjnEqX": {
          "id": "BJqJjnEqX",
          "input": {
            "nodeId": "rySkj3Nq7",
            "pinKey": "ByhGFAotQ"
          },
          "output": {
            "nodeId": "S1WRgJKQqX",
            "pinKey": "__out__"
          }
        },
        "BkHWTn4cm": {
          "id": "BkHWTn4cm",
          "input": {
            "nodeId": "H1uh2sV5Q",
            "pinKey": "HJs8_hoY7"
          },
          "output": {
            "nodeId": "SylWThEcX",
            "pinKey": "ByAIWR_UZ"
          }
        },
        "Bkuoy3kc7": {
          "id": "Bkuoy3kc7",
          "input": {
            "nodeId": "HkGEZcsFm",
            "pinKey": "rk65hdPYX"
          },
          "output": {
            "nodeId": "By8ik3Jc7",
            "pinKey": "Sk450OL-X"
          }
        },
        "By4iKqE9X": {
          "id": "By4iKqE9X",
          "input": {
            "nodeId": "rJr5rw5tm",
            "pinKey": "HyYh1a3LZ"
          },
          "output": {
            "nodeId": "B1y63Fy57",
            "pinKey": "rJFmgJehW"
          }
        },
        "ByAZ6n49m": {
          "id": "ByAZ6n49m",
          "input": {
            "nodeId": "ryd-T3E9Q",
            "pinKey": "BkjI-COLb"
          },
          "output": {
            "nodeId": "SyCekKX5X",
            "pinKey": "B1gI0urv1W"
          }
        },
        "ByN5DLq19m": {
          "id": "ByN5DLq19m",
          "input": {
            "nodeId": "ryZqv85yq7",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "Byg9P8qy9X",
            "pinKey": "S12ezv9tX"
          }
        },
        "ByQWCRaiK7": {
          "id": "ByQWCRaiK7",
          "input": {
            "nodeId": "Sye-CCpsYX",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "HkW00piFm",
            "pinKey": "S12ezv9tX"
          }
        },
        "H1BdWwmcX": {
          "id": "H1BdWwmcX",
          "input": {
            "nodeId": "S1Gd-DXqm",
            "pinKey": "S1yZIA_rDJZ"
          },
          "output": {
            "nodeId": "HJs8WDX9m",
            "pinKey": "HktZUCdrPkZ"
          }
        },
        "H1Eg831qX": {
          "id": "H1Eg831qX",
          "input": {
            "nodeId": "S1_J8h1c7",
            "pinKey": "HyYh1a3LZ"
          },
          "output": {
            "nodeId": "H1eupB3y5X",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "H1ScDIq1q7": {
          "id": "H1ScDIq1q7",
          "input": {
            "nodeId": "Byg9P8qy9X",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "BkM9vI9y5m",
            "pinKey": "__out__"
          }
        },
        "H1nnXLfcQ": {
          "id": "H1nnXLfcQ",
          "input": {
            "nodeId": "rkGrbXIG9Q",
            "pinKey": "HJjEe1lnb"
          },
          "output": {
            "nodeId": "ryZqv85yq7",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "H1qiJ21qm": {
          "id": "H1qiJ21qm",
          "input": {
            "nodeId": "HkGEZcsFm",
            "pinKey": "H1Li3Ovtm"
          },
          "output": {
            "nodeId": "By8ik3Jc7",
            "pinKey": "BkmeFD8OQ"
          }
        },
        "H1xoA0TsFX": {
          "id": "H1xoA0TsFX",
          "input": {
            "nodeId": "HkW00piFm",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "rJj0C6otX",
            "pinKey": "__out__"
          }
        },
        "H1zlanN5m": {
          "id": "H1zlanN5m",
          "input": {
            "nodeId": "BkN9WCg5m",
            "pinKey": "ByAbJsV5X"
          },
          "output": {
            "nodeId": "ByaJ63E9X",
            "pinKey": "HJU8CE2lW"
          }
        },
        "HJCQc3E57": {
          "id": "HJCQc3E57",
          "input": {
            "nodeId": "B1Pmqn4q7",
            "pinKey": "HkXK-dGob"
          },
          "output": {
            "nodeId": "SyCekKX5X",
            "pinKey": "B1gI0urv1W"
          }
        },
        "HJbV5-Rx5X": {
          "id": "HJbV5-Rx5X",
          "input": {
            "nodeId": "BkN9WCg5m",
            "pinKey": "ByhGFAotQ"
          },
          "output": {
            "nodeId": "BJeEcZAxcm",
            "pinKey": "__out__"
          }
        },
        "HJglo24q7": {
          "id": "HJglo24q7",
          "input": {
            "nodeId": "rySkj3Nq7",
            "pinKey": "Syn8hRoFX"
          },
          "output": {
            "nodeId": "rkxAlyYQ97",
            "pinKey": "S13xLCuHvkW"
          }
        },
        "HkCI-D7q7": {
          "id": "HkCI-D7q7",
          "input": {
            "nodeId": "HJs8WDX9m",
            "pinKey": "HJjZLRdBw1-"
          },
          "output": {
            "nodeId": "SkaIf0lqm",
            "pinKey": "BkQzLCurwJZ"
          }
        },
        "HkllLnycX": {
          "id": "HkllLnycX",
          "input": {
            "nodeId": "SJ6JU3k97",
            "pinKey": "HyYh1a3LZ"
          },
          "output": {
            "nodeId": "Bkz1I2y97",
            "pinKey": "r1if8ROSDJ-"
          }
        },
        "Hko5i3Vcm": {
          "id": "Hko5i3Vcm",
          "input": {
            "nodeId": "BkN9WCg5m",
            "pinKey": "Syn8hRoFX"
          },
          "output": {
            "nodeId": "SkaIf0lqm",
            "pinKey": "BkQzLCurwJZ"
          }
        },
        "HymZpnNcm": {
          "id": "HymZpnNcm",
          "input": {
            "nodeId": "SylWThEcX",
            "pinKey": "BkjI-COLb"
          },
          "output": {
            "nodeId": "HJs8WDX9m",
            "pinKey": "HktZUCdrPkZ"
          }
        },
        "S17g83J5Q": {
          "id": "S17g83J5Q",
          "input": {
            "nodeId": "Bkz1I2y97",
            "pinKey": "ry3zLA_Bv1Z"
          },
          "output": {
            "nodeId": "H1eupB3y5X",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "S1BHmpEqX": {
          "id": "S1BHmpEqX",
          "input": {
            "nodeId": "Bk7qP8qJcX",
            "pinKey": "r1sfQ_6fb"
          },
          "output": {
            "nodeId": "rkGrbXIG9Q",
            "pinKey": "rJFmgJehW"
          }
        },
        "S1E-flKy97": {
          "id": "S1E-flKy97",
          "input": {
            "nodeId": "B1MWzxYk57",
            "pinKey": "HyYh1a3LZ"
          },
          "output": {
            "nodeId": "ryWzlKJ57",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "S1HWGxYJ9X": {
          "id": "S1HWGxYJ9X",
          "input": {
            "nodeId": "rybbMlFy5m",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "rygbMlF15m",
            "pinKey": "__out__"
          }
        },
        "S1mdpB3kqX": {
          "id": "S1mdpB3kqX",
          "input": {
            "nodeId": "ByMuarhy57",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "rJWuaB21c7",
            "pinKey": "__out__"
          }
        },
        "SJIZzxFyq7": {
          "id": "SJIZzxFyq7",
          "input": {
            "nodeId": "ryWzlKJ57",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "rybbMlFy5m",
            "pinKey": "S12ezv9tX"
          }
        },
        "SJrzksjkqQ": {
          "id": "SJrzksjkqQ",
          "input": {
            "nodeId": "By-zkojk9m",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "BJgGJoiJ5Q",
            "pinKey": "__out__"
          }
        },
        "SJzp9r2iFm": {
          "id": "SJzp9r2iFm",
          "input": {
            "nodeId": "rJRdWUqK7",
            "pinKey": "HyMSbqjKm"
          },
          "output": {
            "nodeId": "ByZ6cSnsFQ",
            "pinKey": "__out__"
          }
        },
        "Sk0hQIzc7": {
          "id": "Sk0hQIzc7",
          "input": {
            "nodeId": "H1xSbXUz57",
            "pinKey": "HJjEe1lnb"
          },
          "output": {
            "nodeId": "rk7zkookq7",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "SkEGkij19Q": {
          "id": "SkEGkij19Q",
          "input": {
            "nodeId": "rk7zkookq7",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "By-zkojk9m",
            "pinKey": "S12ezv9tX"
          }
        },
        "SkV5faE5X": {
          "id": "SkV5faE5X",
          "input": {
            "nodeId": "Bk7qP8qJcX",
            "pinKey": "SkrgGYLxQ"
          },
          "output": {
            "nodeId": "By2Kz6Eqm",
            "pinKey": "ByAIWR_UZ"
          }
        },
        "SkeT5B2itQ": {
          "id": "SkeT5B2itQ",
          "input": {
            "nodeId": "BkT9B3sKX",
            "pinKey": "__in__"
          },
          "output": {
            "nodeId": "HkGEZcsFm",
            "pinKey": "H1BnItotm"
          }
        },
        "SkmR2sNcX": {
          "id": "SkmR2sNcX",
          "input": {
            "nodeId": "H1uh2sV5Q",
            "pinKey": "rkciKniYm"
          },
          "output": {
            "nodeId": "S1Gd-DXqm",
            "pinKey": "S13xLCuHvkW"
          }
        },
        "SyN_THhycm": {
          "id": "SyN_THhycm",
          "input": {
            "nodeId": "H1eupB3y5X",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "ByMuarhy57",
            "pinKey": "S12ezv9tX"
          }
        },
        "SybZ2hEcm": {
          "id": "SybZ2hEcm",
          "input": {
            "nodeId": "rkxAlyYQ97",
            "pinKey": "S1yZIA_rDJZ"
          },
          "output": {
            "nodeId": "SyCekKX5X",
            "pinKey": "B1gI0urv1W"
          }
        },
        "r1G5GT49Q": {
          "id": "r1G5GT49Q",
          "input": {
            "nodeId": "rkMkojkcm",
            "pinKey": "SkrgGYLxQ"
          },
          "output": {
            "nodeId": "BJyczT45X",
            "pinKey": "ByAIWR_UZ"
          }
        },
        "rJ6YSvcK7": {
          "id": "rJ6YSvcK7",
          "input": {
            "nodeId": "BJ5FSw9KQ",
            "pinKey": "HJJjH2MLQ"
          },
          "output": {
            "nodeId": "rJRdWUqK7",
            "pinKey": "S12ezv9tX"
          }
        },
        "rJXp2tk9X": {
          "id": "rJXp2tk9X",
          "input": {
            "nodeId": "B1y63Fy57",
            "pinKey": "HJjEe1lnb"
          },
          "output": {
            "nodeId": "BJ5FSw9KQ",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "rJihhiNqQ": {
          "id": "rJihhiNqQ",
          "input": {
            "nodeId": "H1uh2sV5Q",
            "pinKey": "SylfrDQcQ"
          },
          "output": {
            "nodeId": "HJnfSP7q7",
            "pinKey": "__out__"
          }
        },
        "rJmS7pN5Q": {
          "id": "rJmS7pN5Q",
          "input": {
            "nodeId": "rkp3CpiY7",
            "pinKey": "r1sfQ_6fb"
          },
          "output": {
            "nodeId": "r1VBbX8z97",
            "pinKey": "rJFmgJehW"
          }
        },
        "rkBPMReq7": {
          "id": "rkBPMReq7",
          "input": {
            "nodeId": "SkaIf0lqm",
            "pinKey": "B1GfLR_SPk-"
          },
          "output": {
            "nodeId": "r1ytkRgcX",
            "pinKey": "S10ecHDUW"
          }
        },
        "rkDfX8f9X": {
          "id": "rkDfX8f9X",
          "input": {
            "nodeId": "r1VBbX8z97",
            "pinKey": "HJjEe1lnb"
          },
          "output": {
            "nodeId": "Sye-CCpsYX",
            "pinKey": "HkxkiS3f8Q"
          }
        },
        "ry95fp4q7": {
          "id": "ry95fp4q7",
          "input": {
            "nodeId": "BJyczT45X",
            "pinKey": "BkjI-COLb"
          },
          "output": {
            "nodeId": "H1xSbXUz57",
            "pinKey": "rJFmgJehW"
          }
        },
        "ryrot9VcQ": {
          "id": "ryrot9VcQ",
          "input": {
            "nodeId": "SklakFJcX",
            "pinKey": "HyYh1a3LZ"
          },
          "output": {
            "nodeId": "B1y63Fy57",
            "pinKey": "rJFmgJehW"
          }
        }
      },
      "nodes": {
        "B1MWzxYk57": {
          "boundLiterals": {
            "B1oqkTnIb": "D13"
          },
          "id": "B1MWzxYk57",
          "label": "Second floor",
          "position": {
            "x": 408,
            "y": 1020
          },
          "type": "xod/common-hardware/led"
        },
        "B1Pmqn4q7": {
          "id": "B1Pmqn4q7",
          "position": {
            "x": 2346,
            "y": 816
          },
          "size": {
            "height": 51,
            "width": 238
          },
          "type": "xod/core/watch"
        },
        "B1y63Fy57": {
          "boundLiterals": {
            "B1rSeJlnZ": "255",
            "HkFBgJehW": "1"
          },
          "id": "B1y63Fy57",
          "position": {
            "x": 544,
            "y": 1020
          },
          "type": "xod/math/map-clip"
        },
        "BJ5FSw9KQ": {
          "id": "BJ5FSw9KQ",
          "position": {
            "x": 544,
            "y": 918
          },
          "type": "gabbapeople/uart-led-control/parse-number"
        },
        "BJDKG6457": {
          "id": "BJDKG6457",
          "position": {
            "x": 1122,
            "y": 1122
          },
          "type": "xod/core/pulse-on-change"
        },
        "BJeEcZAxcm": {
          "id": "BJeEcZAxcm",
...

This file has been truncated, please download it to see its full contents.

Description:

Scheme
Scheme bb nvzxh1qwsx


YOU MIGHT ALSO LIKE