Category: NodeMCU

The new BI2 black vibrator development board

The new black BI2 board is ready. I have a few assembled boards ready for shipping. Have a look at www.tindie.com

3 JST 1mm plugs (battery, motor 2, motor 3), LED, reset button, M+/M- is for motor 1

JST 1mm plug for motor 1, alternative RESET button

Features

  • ESP8266 Microcontroller with WLAN
  • MPU9250 (accelerometer, gyroscope)
  • LiPo battery charging
  • 3 motors can be connected (simple motor driver circuits)
  • 1 WS2812B LED – a  colourful LED (16 Mill. colours). They are commonly known as Adafruit Neopixel – a strip or a ring of individual programmable LEDs (when use the WS2812B only two motors can be connected)
  • design based on the great Adafruit Feather Huzaah ESP8266
  • vibration motors and LiPo battery can be easily connected with JST 1mm connectors
  • two reset buttons (the button next to the USB connector can be overmolded)
  • USB connector for battery charging and code uploading
  • programmable with the Arduino IDE or NodeMCU
  • white LED for indicating charging
  • standard LED (yellow) on GPIO00
  • round 40mm diameter

 

There are 3 free GPIO ports. Standard layout are for driving 2 motors (GPIO 12 = M2, GPIO 13 = M3) and 1 LED (GPIO14). Alternatively you can use 3 motors (GPIO12,13,14) but no LED.

Standard: SJ2 not connected, SJ3 connected

Alternative: SJ2 connected, SJ3 not connected

 

Here is the schematic which is adapted from Adafruit.

References:

  • Quick start up guide with Blynk app is here
  •  Assembling a silicone molded vibrator with 3D printed form – tutorial here
  • Complete guide including wireless charging, control with Node-RED and data transmission via MQTT is here

Basic Node for the Internet of Sex Toys (part 1)

Wemos mini modules: ESP8266, motor driver and battery charging (in the middle); Wireless charging module (right side); wireless charging coil (top side); encapsulated vibration motors (left side)

In previous posts we showed how to build a vibrating sex toy in principle as part of the Internet of Things (IOT). In addition we have selected a hardware platform – the popular ESP8266 – for controlling a vibrator motor, gathering motion data and connecting to the internet. Now we want to build the toy itself.

part 1: Basic Node for the Internet of Sex Toys

part 2: Molding the Basic Node

part 3: Software for the Basic Node

Brief Review of development boards

There are a lot of development boards which are equipped with the ESP8266. The popular NodeMCU was already introduced here. Here is a quick overview and comparison:

NodeMCU

  • plus: very popular, cheap, USB connector for programming
  • minus: quite large (for being part of a sex toy), no support for battery charging

Adafruit Feather Huzaah ESP

  • plus: USB connector for programming and battery charging, smart form factor (only 23 mm wide), very good support (libraries, tutorials)
  • minus: quite expensive

WeMos D1 mini (pro)

  • plus: very cheap, USB connector for programming, additional stackable modules (eg. battery charging, TFT screens, motor driver), good form factor
  • minus: no real support (but there is a forum, problems with modules reported

ESP8285 (variant of the ESP8266)

  • plus: really small (!!!) and smart form factor, USB programming and battery charging, optional sensors on board (but no motion sensors)
  • minus: quite expensive, only 1MB memory (nevertheless enough for a lot of application)

For our project we selected the WeMos mini cause we get almost everything we need:

  • USB connector for programming
  • module for battery charging
  • module for a motor driver
  • good form factor (eg. to be put in a vibrator handle or in the base of a dildo)
  • cheap, fast delivery

But there is no shield for motion detection (accelerometer,gyroscope). So we have to use an additional board eg equipped with the MPU9250.

But there is a problem with the WeMos motor shield: After a few seconds it stopped working. And in addition the MPU9250 stopped working, too. Hours and hours we tried different configurations, changed the libraries … The problem was the motor driver shield itself. Fortunately there is an easy work around. Read here.

Another issue is the battery shield. It has an extra USB connector for charging the battery. So you have two USB connectors (one for battery charging and one for uploading). Two USB connectors are not handy. Fortunately we can do without the USB connector for uploading as it is possible to update the software over the air (OTA) using WiFi.

Material

As the body interaction philosophy uses motion for controlling the device we have to add the MPU. Again we use the MPU9250 which has an accelerometer, gyroscope and magnetometer.

Another insight was that you need at least a switch for rebooting. As we want to mold everything the switch must meet the IP67 requirements, which means it is water- (and silicone) proof. If you don’t want to mold the electronics you can use the RESET button on the WeMos mini board.

A perfect basic node has a wireless charging option, too.

Material list for the basic node:

  • Wemos mini board
  • Wemos motor driver shield
  • Wemos battery shield
  • Wemos prototyping board
  • Wemos set of pins
  • LiPo battery (eg. 3,7V 650mAh, 2C, JST plug, available at ebay)
  • MPU 9250 board (for motion control)
  • 1 or 2 encapsulated vibration motors, 3V, available at Alibabaexpress
  • Optional: Switch IP 67 protected (eg. Cherry Switches DC1C-K8AA IP67) – for molding
  • Optional: Wireless charging receiver 5V eg from Seeed Studio

Material: battery shield, Wemos mini ESP8266, motor shield, MCU9250 (first row), LiPo battery, switch, vibration motor (second row)

 

Soldering the basic node

We use one connector (part of the Wemos set of pins) to connect the Wemos mini with the battery shield and the motor shield. This is done to save space. If your application has enough space you would use one connector for every shield.

Battery shield, Wemos mini ESP 8266, motor shield (from top to bottom)

Now have a look at the bottom side where the motor shield should be. We can connect up to 2 motors. Solder motor 1 to A1 and A2. Motor 2 has to be soldered to B1 and B2. In addition we need input power for the motor. We just use the 5V provided by the Wemos mini battery shield. Connect 5V to VM and GND (from the pins) and GND. But you could use other (more powerful) power sources, too.

Wemos offers a prototyping board. We use it for mounting the switch and for the MPU9250. Connect the MPU9250 to the bottom side of the prototyping board. Therefore 4 pins have to be soldered

Solder pin (1 row, 4 pins)  on the top side next to TX, RX, D1, D2

 

Now look at the bottom side of the prototyping board. Put the MPU 9250 so that VCC, GND, SDA, SCL are connected to the pins.

Next, solder the MPU 9250.

Then add more pins to the prototyping board at both sides. The picture shows the bottom side of the prototyping board.

Now wire the prototyping board. The picture shows the top side.

Now you can add the switch. Place it in the middle of the board on the top side. Connect GND and RST to the switch. Now you have a switch for rebooting which can be molded.

Now we have both parts ready and can stack them together.

Stack them together!

Now add the LiPo battery, which should have a JST header. Now your basic node is ready.

Wireless charging option

Especially for sex toys a wireless charging option is reasonable as this is a requirement for silicone molding of the toy.  And when the toy is molded it is safe and washable.

The wireless charging module consists of a sender (or transmitter module) and a receiver module. You have to solder the receiver module to the battery shield. Don’t mix the modules.

unfortunately there is only  a USB connector. If you don’t want to remove the USB connector you can solder the red (+) wire to the R330 resistor as shown on the pictures. The black (-) wire can be soldered to any pin labeled (GND).

Now put the receiver module on top of the battery module.

Now stack the protoytping board on top of the battery shield.  And connect the battery.To charge the battery connect the sender (or transmitter) module to 5V. To power the sender module you may use a USB port power source which has about 500mAh or more. Place sender and receiver coil about each other.  For a more professional charging solution you need a charging station. The making of a charging station using 3d printing is described here.

Learn how to construct the mold form in part 2:

part 2: Molding the basic node

part 3: Software for the basic node

Internet of (sex) things – part 4: Building a sex toy dashboard with Node-RED

In the fourth part of the tutorial we explain the development of a dashboard for our sex toy.

The series has 4 parts:

part 1: Exploring the internet of (sex) things

part 2: MQTT messages

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

The dashboard is used to visualize certain data eg. the speed of the vibration motor and the movements of the vibrator. In addition it can have some control elements eg. for changing the vibration pattern.

ui-all

The window above is called a tab. You can have multiple tabs. The Motor, Data, Status and Controls – windows are called groups. The Controls – group has buttons to set the motor mode. In addition there is a slider which will set the motor to a constant speed. And there is an on/off button for the LED.

You have to install the Node-RED dashboard. Therefore you need at least version 0.14 of Node-RED. At the time this text was written the standard Node-RED installation is version 0.13 which is not sufficient for the dashboard.

Therefore check your Node-RED version. If it is equal or better than 0.14, skip this step:

  • Download & unzip the latest version from github (eg. https://github.com/node-red/node-red/releases/tag/0.15.2).
  • Now change to newly created directory eg “node-red-0.15.2”
  • On Windows: Start a command shell in adminstration mode
  • Execute “npm install” to install Node-RED.

If your Node-RED version is 0.14 or better install the dashboard:

Some  remarks:

Let’s start and have a look at the new Node-RED interface: On the left side you will find the dashboard or user interface nodes. And on the right side there is new dashboard – tab. It contains all dashboard nodes which are used in the flow ordered hierarchical.

node-red-ui

But where is the dashboard? Just open your browser and go to one of the URLs:

http://localhost:1880/ui/#/0 or
http://127.0.0.1:1880/ui/#/0

How can I get all the flows? You can download all flows here: bi-ui-node-red. Unzip the file and you will get a text file. Open the text file in an editor. Select the text and copy it to the clipboard.

Now we will explain two flows in detail.

Now go the Node-RED window, open the menu (it is on the left top side), select Import -> Clipboard.import1

A new window will open where you can insert the text (CTRL+V). Then press the Import-button.

import2

nodemcu prototype breadboardThe Arduino sketch was updated for the dashboard. Please download the Arduino sketch from here: iost-part4-v12. Unzip the file. Compile and upload to your hardware (see part 1 of the tutorial).

 

In the first flow we will receive some vibration motor sex toy data which are sent by the MQTT protocol. We will display the data using a gauge and a graph element.

Let’ start with the MQTT input node. There is nothing new. Just connect to the MQTT server and subscribe the topic “BIoutTopic2” – which the sex toy uses to send out data.mqtt-in

Now add the function node “JSON” which will parse the incoming message and places the result in “payload”.

But we want to know the motor speed only. Therefore we need a function node which passes the vibration motor speed as payload and deletes all other data. Please use the following JavaScript code:

get-motor-speed-function-node

To display the speed we need to more nodes. The gauge node gauge-node displays the actual speed. Connect the gauge node with the function node. You can add the range – the minimum and maximum value (0 and 1023).motor-gauge

 

Now add a chart node chart-nodeand connect it with the function node, too.

 

Next we want the chart node and the gauge node to be together as shown in the next image.

motor

We have to make a group and put both nodes into the group. Have a look on the dashboard at the right side. Make a new group and move the gauge and chart node below the group called “Motor”.

dashboard-top

slider-nodeNow we explain the second flow. It is used to send commands to the sex toy. We will use a slider to control the speed. But there is one problem: the slider should display the actual speed of the vibration motor. Therefore we manipulate the slider. To display the actual motor speed we have to move the slider appropriate to the actual speed. The slider will be part of the control group:

controls

Now get the slider node and edit the node as follows:

slider-motor-speed

Then connect the node with the “get motor speed” function which was introduced in the first flow.

construct-json-motor-speed-function-nodeFinally comes the trick part. Get a new function node and connect it with the slider. This node will construct the JSON message which will be sent to the sex toy using MQTT. The JavaScript code of the function node is as follows:

function-node-for-constructing-json-speed-command

msg.payload={messageType:"execute", actuator:"motor1",
             actuatorMode:"constant", actuatorValue:msg.payload}
msg.topic = "BIinTopic";
return msg;

Now connect the function node with a new MQTT output node. Leave the topic empty as it will be passed from the input nodes:

mqtt-out-message-to-bi

Using Node-RED with the Node-RED dashboard we are able to make a user interface for our sex toy(s). We could easily display the motion of the sex toy as well as the vibration motor speed. You could argue that we had a (very simple) user interface already in part 1 of the tutorial, without having to use MQTT, Node-RED and the Node-RED dashboard. That’s true. But imagine you have several sex toys and want to control them. You could easily add a tab in Node-RED for each sex toy. Or you could build more sophisticated flows incorporating several sex toy. Why not interconnecting the vibrating necklace with a penis ring and one of the plugs or dildos?

There are a lot of flows and nodes already available at http://flows.nodered.org/. (Of course not in the sex toy domain)

Why not play music for a given sex toy vibrator mode? Or control the sex toy using another IOT device…

Internet of (sex) things – part 2: MQTT messages

In the first IOT tutorial we have shown how to build a sex toy based on a ESP8266 MCU.

There are two more parts of this tutorial series:

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

The ESP8266 is a microcontroller which can connect to the internet. You can write sketches with the Arduino IDE and connect a lot of actuator modules (like vibration motors, displays) and sensors (motion detection).

nodemcu prototype breadboard

In the first approach a web server was installed on the ESP8266. Control was possible by browsing to the web server, which could be accessed by a computer or smart phone using the same WiFi Access Point (AP).

browser vibrator control

In this second tutorial we will connect the ESP8266 to the internet and publish and receive data as well as commands by internet.

Protocols

There are some protocols for publishing (sending) data. We use the MQTT protocol which is very fast and suited for short messages. In addition we need a MQTT server. We will send the ESP8266 data to the server. And the ESP8266 can receive data (or commands) from the server. Other services can connect to the MQTT server, too. In this tutorial we will use a MQTT client which can display the sex toy data and send commands to the ESP8266.

mqtt-diagramm

Sex toy data exchange format

A big disadvantage of commercial sex toys is their proprietary data exchange formats. Kyle Machutis developed buttplug.io a Cross Platform Framework for Sex Toy Control to overcome this issue.

For this IOT project we will use the JSON format which is a very simple way to exchange data:

This is an example for the message type “sensor”. It says that the fusioned sensor data of the “mps9250” MPU is 5657, the LED is off (0), the motor is in mode sinus curve (2) and the speed of the vibration motor is 766.

{"messageType":"sensor",
"sensor":"mps9250",
"fusionedData":5675,
"messageNumber":8,
"LEDstatus":0,
"motor1mode":2,
"motor1speed":766}

There are three message types: sensor, execute and message.

  • Sensor is for publishing sensor data to everyone who is interested in that.
  • Execute is for controlling a specific device, eg for turning the motor on.
  • Message sends a text message to specific device. If the deviceID is not given it will be sent to all receivers,

For this project we need the

  • hardware from part 1 of the IOT project
  • the Arduino library JSON for parsing and encoding exchange data
  • a library for sending and receiving MQTT data
  • the mqtt-spy software to send and receive MQTT messages
  • optional: a MQTTserver like mosquitto

Arduino JSON library

There is a great library which can parse and build JSON files. Here is the documentation: https://github.com/bblanchon/ArduinoJson

Please go into the Arduino library manager and install the JSON package.

Arduino PubSubClient library

In addition we need a package for sending and receiving MQTT messages. You will find the PubSubClient library in the library manager, too.

Documentation: https://github.com/bblanchon/ArduinoJson

You have to change the maximum length of a message. By default it is only 128. Search for the file PubSubClient.h and change MQTT_MAX_PACKET_SIZE to 1024. On my Win10 system the file is located at

C:\Users\...\Documents\Arduino\libraries\PubSubClient\src\PubSubClient.h

Change the following line:

// MQTT_MAX_PACKET_SIZE : Maximum packet size
 #define MQTT_MAX_PACKET_SIZE 1024

MQTT-SPY software

This is an excellent piece of software which can connect to a MQTT server and send and receive messages: mqtt.spy. We use it to test the connection from the ESP8266 to the mosquitto server and for debugging our vibrator toy control software on the ESP8266.

Download from https://github.com/kamilfb/mqtt-spy/wiki/Downloads

If you haven’t your own MQTT server, you can use the Mosquito test server (only for testing, don’t spam them). Start mqtt-spy and connect to “test.mosquito.org”.

mqtt-start-screen

Subscription of messages: To receive the messages from the ESP8266  you have to subscribe to a topic. Use the same topic as in the source code, eg. “BIoutTopic”. You have to select the “New”-tab in the subscription, a new window pops up. Enter “BIoutTopic”. Now you receive all messages from the ESP8266.mqtt-client

Publishing messages: In the upper part of the window enter “BIinTopic”. In the “data” field you enter commands which will be sent to the ESP8266. Enter the commands and press “Publish”.

subscription-windowTry it out. Here are some examples:

JSON data exchange & command examples

Send message:

{
 messageType : "message",
 message : " Hello world!"
 }

Send Command – LED on:

{
 messageType : "execute",
 actuator : "LED",
 actuatorValue : 1
 }

Send command – motor1 modus is set to sinus curve vibration pattern

{
 messageType : "execute",
 actuator : "motor1",
 actuatorMode : "sinus"
 }

Send Command – set motor speed to 1000.

{
 messageType : "execute",
 actuator : "motor1",
 actuatorValue: 1000
 }

Send command – set motor1 off.

{
 messageType : "execute",
 actuator : "motor1",
 actuatorMode: "off"
 }

Message type “sensor”: this is for publishing sensor data of a sex toy (eg. position in 3d space, movement data, vibration pattern in use). These data can be received by other sex toys for vibration adjustment and synchronization of the vibration speed .

{
 messageType : "sensor",
 sensor: "mps9250",
 fusionedData: 10000,
 }

Remark: If it doesn’t work as expected, check the data field of the MQTT software. Paste & Copy doesn’t work as it should be and you may have to remove some redundant “{“-signs.

Code

The code is based on part 1. In the new code functions for publishing and receiving JSON data over MQTT are added.

Receiving and parsing incoming JSON files is done in “callback”. “callback” will be executed whenever a MQTT message comes in.

void callback(char* topic, byte* payload, unsigned int length) {

At first the incoming message is parsed and the result is stored in “root”. Now each entry in the JSON file can be accessed by assigning a new variable to root[entry]:

StaticJsonBuffer<500> jsonBuffer;
 JsonObject& root = jsonBuffer.parseObject(s);
 if (!root.success()) {
 Serial.println("parseObject() failed");
 } 
 String messageType = root["messageType"];

Build and publishing JSON files is done in the loop. A JsonObject “root” is created and then each entry in the JSON file is added by an assignment to root eg:  root[“messageType”] = “sensor”:

StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["messageType"] = "sensor"; // execute, message, sensor

For producing the JSON file there is “printTo” function. The JSON array of char must be formatted with the snprintf() function and then it can be published.

 root.printTo(outMsg, sizeof(outMsg));
 snprintf (msg,1000, "%s",outMsg);
 mqttclient.publish("BIoutTopic", msg);

Download the zipped and formatted code here: nodemcu-server-mqtt-iot.

In the next part of the tutorial we use Node-RED for visual programming our IOT sex toys.

Here is the complete source code for part 2 of the tutorial.

// bodyinteraction IOT project
// IOT sex toy prototype - control via browser and MQTT
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0x0C

#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18

#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18

const char* ssid = "ALICE-WLAN";
const char* password = "36s69c3756a65";
const char* mqtt_server = "test.mosquitto.org";

int ledPin = 0; // NodeMCU pad D3 = GPIO 0
int motorPin= 13; // NodeMCU pad D7 = GPIO 13
double sinusValue=0;

// define constants for four different vibration modes
const int offMode=0;
const int maxMode=1;
const int sinusMode=2;
const int motionMode=3;

int motorMode =offMode; //current mode
int motionVector = 0; //current fusioned motion
// Acceleration in x,y and z direction at t(ime)=1 and time=0
// Geroscop data
int16_t ax,ay,az,ax1,ay1,az1,gx,gy,gz,gx1,gy1,gz1;
int valueMotor; //vibrator motor speed 0-1023

WiFiServer server(80);

WiFiClient espclient;
PubSubClient mqttclient(espclient);
char msg[512];
char outMsg[512];

bool requesting=false; // is there a request eg button pressed on webpage

//timing of mqtt messages
long now=0;
long lastMsg = 0;


int value = 0;
int valueLED = LOW;

// This function read Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.endTransmission();

// Read Nbytes
Wire.requestFrom(Address, Nbytes);
uint8_t index=0;
while (Wire.available())
Data[index++]=Wire.read();
}

// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}



// Return the response /generate webpage
void generateWebpage(WiFiClient espclient) {
espclient.println("HTTP/1.1 200 OK");
espclient.println("Content-Type: text/html");
espclient.println(""); // do not forget this one
espclient.println("<!DOCTYPE HTML>");
espclient.println("<html>");

espclient.print("Led pin is now: ");

if(valueLED == HIGH) {
espclient.print("On");
} else {
espclient.print("Off");
}

espclient.print("
Motor pin is now: ");
espclient.print(valueMotor);

espclient.println("

");
espclient.println("<a href=\"/LED=ON\"\"><button>Turn On </button></a>");
espclient.println("<a href=\"/LED=OFF\"\"><button>Turn Off </button></a>

");
espclient.println("<a href=\"/MOTOR=MAX\"\"><button>Motor Max </button></a>");
espclient.println("<a href=\"/MOTOR=OFF\"\"><button>Motor Off </button></a>");
espclient.println("<a href=\"/MOTOR=SINUS\"\"><button>Motor sinus curve </button></a>");
espclient.println("<a href=\"/MOTOR=MOTION\"\"><button>Motor motion controlled </button></a>
");
espclient.println("</html>");
}

// function callback is executed when a Mqtt message comes in
// - prints mqtt message
// - parse JSON file
// - execute commands
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
char s[length];
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
s[i]=payload[i];
}
StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(s);
if (!root.success()) {
Serial.println("parseObject() failed");
}
String messageType = root["messageType"]; //sensor, execute , message
String targetDeviceID = root["targetDeviceID"];
String actuator = root["actuator"];
int actuatorValue = root["actuatorValue"];
String actuatorMode = root["actuatorMode"];
String message = root["message"];
Serial.print("messageType: ");
Serial.println(messageType);
Serial.print("actuator: ");
Serial.println(actuator);
Serial.print("actuatorValue: ");
Serial.println(actuatorValue);

// print message
if (messageType=="message") {
Serial.print("Incoming message: ");
Serial.println(message);
}
// LED commands
if (messageType=="execute"&&actuator=="LED"&&actuatorValue==1) {
Serial.println("LED on received");
digitalWrite(ledPin, HIGH);
valueLED = HIGH;
}
if (messageType=="execute"&&actuator=="LED"&&actuatorValue==0) {
Serial.println("LED off received");
digitalWrite(ledPin, LOW);
valueLED = LOW;
}
// set modes commands
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="off") {
analogWrite(motorPin, 0);
valueMotor = 0;
motorMode=offMode;
}
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="sinus") {
motorMode=sinusMode;
}
if (messageType=="execute"&&actuator=="motor1"&&actuatorMode=="motion") {
motorMode=motionMode;
valueMotor=600;
if (valueMotor<500) {valueMotor=500;} if (valueMotor>1023) {valueMotor=1023;}
}
// set motor speed command
if (messageType=="execute"&&actuator=="motor1"&&actuatorValue!=0) {
Serial.println("set motor speed to fixed value");
valueMotor=actuatorValue;
analogWrite(motorPin,valueMotor);
}
// incoming sensor data, adjust motor speed when in motion mode
int fusionedData = root["fusionedData"];
String sensor = root["sensor"];
if (messageType=="sensor"&&sensor=="mps9250"&&motorMode==motionMode) {
if (fusionedData > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
if (valueMotor<500) {valueMotor=500;} //values must be above 500 otherwise the motor is off if (valueMotor>1023) {valueMotor=1023;} // values higher than 1023 are not supported
analogWrite(motorPin, valueMotor); // set motor speed
}
generateWebpage(espclient);
}

// connect to mqtt server
void reconnect() {
while (!mqttclient.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (mqttclient.connect(clientId.c_str())) {
Serial.println("connected");
mqttclient.subscribe("BIinTopic");
} else {
Serial.print("failed, rc=");
Serial.print(mqttclient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}

void setup() {
Wire.begin();
// connect MPU9265 via i²c bus
// NodeMCU D1 = GPIO5 connected to MCU9265 SCL
// NodeMCU D2 = GPIO4 connected to MCU9265 SDA
Wire.pins(5,4);
Serial.begin(115200);

// Configure gyroscope range
I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
// Configure accelerometers range
I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
// Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);

// Request first magnetometer single measurement
I2CwriteByte(MAG_ADDRESS,0x0A,0x01);

Serial.begin(115200);
delay(10);

// init LED pin
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);

// init motor pin
pinMode(motorPin, OUTPUT);
analogWrite(motorPin, 0);

// Connect to WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");

// Start the server
server.begin();
Serial.println("Server started");

// Print the IP address
Serial.print("Use this URL to connect: ");
Serial.print("http://");
Serial.print(WiFi.localIP());
Serial.println("/");

// init mqtt client
mqttclient.setServer(mqtt_server, 1883);
mqttclient.setCallback(callback);
}

void loop() {
if (!mqttclient.connected()) {
reconnect();
}
mqttclient.loop();

// Read accelerometer and gyroscope
uint8_t Buf[14];
I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);

// Create 16 bits values from 8 bits data

// Accelerometer
ax=-(Buf[0]<<8 | Buf[1]);
ay=-(Buf[2]<<8 | Buf[3]);
az=Buf[4]<<8 | Buf[5];

// Gyroscope
gx=-(Buf[8]<<8 | Buf[9]);
gy=-(Buf[10]<<8 | Buf[11]);
gz=Buf[12]<<8 | Buf[13]; // when in "motionMode" the vibration motor is controlled by motion if (motorMode==motionMode) { motionVector=sqrt(pow(ax-ax1,2)+pow(ay-ay1,2)+pow(az-az1,2)); //calculate motion vector // adjust vibration motor speed // if motion vector > 5000 raise speed by 25
// otherwise lover speed by 10
// adjust these constants to your needs
if (motionVector > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
if (valueMotor<500) {valueMotor=500;} //values must be above 500 otherwise the motor is off if (valueMotor>1023) {valueMotor=1023;} // values higher than 1023 are not supported
analogWrite(motorPin, valueMotor); // set motor speed

Serial.print("motionVector: ");
Serial.print(motionVector);
Serial.print(", valueMotor: ");
Serial.println(valueMotor);
delay(200);

// save values
ax1=ax;
ay1=ay;
az1=az;
gx1=gx;
gy1=gy;
gz1=gz;
}

// change vibration motor speed according to a sinus curve
if (motorMode==sinusMode) {
sinusValue=sinusValue+.01;
delay(20);
int sinTmp = ((sin(sinusValue)+1)*.5*(1023-500))+500;
analogWrite(motorPin, sinTmp);
valueMotor=sinTmp;
}

StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["messageType"] = "sensor"; // execute, message, sensor
// execute - send command to other device
// root["targetDeviceID"] = "xxxxx"; //for execute and message message types
// root["actuator"] = "motor1";
// root["actuatorValue"]="222";
// root["actuatorMode"] = "sinus";
// root["command"] = none;
// root["commandParameter1"] ="";

// message - send message to targetDeviceID
// root["message"] = "hello world";

//sensor - for publishing sensor data
root["sensor"] = "mps9250";
// root["time"] = none;
root["fusionedData"] = motionVector;
root["messageNumber"] = 0;
// example for raw data
// JsonArray& rawdata = root.createNestedArray("rawdata"); // x,y,z,roll, pitch better??
// rawdata.add(0, 0); // ax
// rawdata.add(0, 0); // ay
// rawdata.add(0, 0); // az
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // gx
// rawdata.add(0, 0); // mx
// rawdata.add(0, 0); // mx
// rawdata.add(0, 0); //mx
root["LEDstatus"] = valueLED;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;

// publish motor speed as mqtt message every 10 seconds
// only when motor in not off
if (motorMode==maxMode||motorMode==sinusMode||motorMode==motionMode) {
now = millis();
if (now - lastMsg > 1000) {
if (!mqttclient.connected()) {
reconnect();
}
lastMsg = now;
++value;
root["messageNumber"] = value;
// publish data as MQTT message in JSON format
root.printTo(outMsg, sizeof(outMsg));
snprintf (msg, 1000, "%s",outMsg);
mqttclient.publish("BIoutTopic", msg);
Serial.print("Publish message every 10 sec: ");
Serial.println(msg);
}
}

// Check if a client has connected to the wifi server
WiFiClient espclient = server.available();
if (!espclient) {
return;
}

while(!espclient.available()){
delay(1);
}

// read the first line of the request
String request = espclient.readStringUntil('\r');
espclient.flush();

// LED on button pressed
Serial.println("hi execute rqeuest");
if (request.indexOf("/LED=ON") != -1) {
requesting=true;
digitalWrite(ledPin, HIGH);
valueLED = HIGH;
root["LEDstatus"] = valueLED;
}
// LED off button pressed
if (request.indexOf("/LED=OFF") != -1) {
requesting=true;
digitalWrite(ledPin, LOW);
valueLED = LOW;
root["LEDstatus"] = valueLED;
}
// set motor to maximum speed button pressed
if (request.indexOf("/MOTOR=MAX") != -1) {
requesting=true;
analogWrite(motorPin, 1023);
valueMotor = 1023;
motorMode=maxMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// set motor off button pressed
if (request.indexOf("/MOTOR=OFF") != -1) {
requesting=true;
analogWrite(motorPin, 0);
valueMotor = 0;
motorMode=offMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// motor amplitude controlled like a sinus curve
if (request.indexOf("/MOTOR=SINUS") != -1) {
requesting=true;
motorMode=sinusMode;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}
// motor speed is adjusted by movements (classical "body interaction" interaction pattern)
if (request.indexOf("/MOTOR=MOTION") != -1) {
requesting=true;
motorMode=motionMode;
valueMotor=600;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;
}


generateWebpage(espclient);

// send outMessage to Mqtt server
if (requesting) {
requesting=false;
if (!mqttclient.connected()) {
reconnect();
}
++value;

root["messageNumber"] = value;
root["motor1mode"] = motorMode;
root["motor1speed"] = valueMotor;

// publish data as MQTT message in JSON format
root.printTo(outMsg, sizeof(outMsg));
snprintf (msg,1000, "%s",outMsg);
mqttclient.publish("BIoutTopic", msg);

Serial.print("Publish message: ");
Serial.println(msg);
}
}

Exploring the internet of (sex) things 1

The internet of things – or short IOT – is getting popular. IOT is a network of physical things like vehicles, buildings, but also everyday objects like lamps, refrigerators. IOT allows objects to be sensed and controlled remotely across the Internet. As a result the physical world will be integrated into the internet and computer systems.

Popular examples are home axiomatization or collection of environmental data.  Even sex toy industry use the internet to connect sex toy users which are far away of each other (like the OhMiBod blueMotion). The vision of remote sex driven by technology is also known as Teledildonics. Unfortunately I didn’t pay much attention to this movement which goes back to 1975. body interaction focused more on wireless connected sex toys for users having sex together and want to integrate his and her’s sex toy. You will find a lot of information at Kyle Machulis site Metafetish. Also have a look at the annual conference Arse Elektronika which focus on the intersection of technology and sex.

In this blog I have already shown how to connect the body interaction development board to the internet. Now I will present some first steps into IOT. I will use the NodeMCU development board which is based on the popular ESP8266 System on a chip. The ESP is a wi-fi enabled microcontroller where you can connect sensors and actuators. It can connect to your wi-fi access point and home and it can be an access point itself and host eg. an internet server.

In my explorations I will try to find out if a IOT sex toy is useful for DIY sex toy community.

In this blog post we will use the ESP8266 as a wi-fi server. The server will connect to your wi-fi access point at home.

The series has 4 parts:

part 1: Exploring the internet of (sex) things

part 2: MQTT messages

part 3: Node-RED

part 4: Building a sex toy dashboard with Node-RED

Building a bread board prototype

nodemcu prototype breadboard

Material needed

  • bread board, wires
  • Node MCU or similar
  • small vibration motor (or LED), eg the Lilipad vibration motor
  • optional: accelerometer  MPU9265
  • optional: another LED and a resistor

WIre MPU9265

mpu-92-65Connect

  • SCL (on MPU9265) and D1 (on NodeMCU),
  • SDA and D2,
  • VCC and 3V3
  • GND and GND

Wire vibration motor

Connect

  • D7 (node MCU) with vibration motor (+) and
  • GND (NodeMCU) and (-)

Wire LED

Connect:

  • D3 (NodeMCU) and LED (long end)
  • LED (short end) and resistor
  • resistor and GND (NodeMCU)

Using the Arduino IDE

NodeMCU and all other ESP8266 boards are not supported by Arduino. But you can use the Arduino board manager to add other development boards. This short Tutorial explains the necessary steps: http://www.instructables.com/id/Quick-Start-to-Nodemcu-ESP8266-on-Arduino-IDE/

Connect the NodeMCU to your access point (WLAN router)

Upload script to NodeMCU

Copy the code below to the Arduino IDE or download and unzip this Arduino “.ino” file.

Within the sketch you have to change the constants SSID and password. Use the same SSID as you would do to connect your smart phone or computer to the internet.

Select your NodeMCU and the port. Connect your computer and the NodeMCU with USB wire. Upload the script to NodeMCU

#include <ESP8266WiFi.h>
#include <Wire.h>

#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0x0C

#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18

#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18

const char* ssid = "????"; // Enter the name of your Access point
const char* password = "????"; //Enter the password SSID
int ledPin = 0; // NodeMCU pad D3 = GPI0
int motorPin= 13; // NodeMCU pad D7 = GPIO 13
double sinusValue=0;

// define constants for four different vibration modes
const int off_mode=0;
const int max_mode =1;
const int sinus_mode =2;
const int motion_mode =3;

int motor_mode =off_mode;

WiFiServer server(80);

 // This function read Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
 // Set register address
 Wire.beginTransmission(Address);
 Wire.write(Register);
 Wire.endTransmission();

 // Read Nbytes
 Wire.requestFrom(Address, Nbytes);
 uint8_t index=0;
 while (Wire.available())
 Data[index++]=Wire.read();
}

// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
 // Set register address
 Wire.beginTransmission(Address);
 Wire.write(Register);
 Wire.write(Data);
 Wire.endTransmission();
}

void setup() {

 Wire.begin();
 // NodeMCU D1 = GPIO5 connected to MCU9265 SCL
 // NodeMCU D2 = GPIO4 connected to MCU9265 SDA
 Wire.pins(5,4);
 Serial.begin(115200);

 // Configure gyroscope range
 I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
 // Configure accelerometers range
 I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
 // Set by pass mode for the magnetometers
 I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);

 // Request first magnetometer single measurement
 I2CwriteByte(MAG_ADDRESS,0x0A,0x01);

 Serial.begin(115200);
 delay(10);

 pinMode(ledPin, OUTPUT);
 digitalWrite(ledPin, LOW);

 pinMode(motorPin, OUTPUT);
 analogWrite(motorPin, 0);

 // Connect to WiFi network
 Serial.println();
 Serial.println();
 Serial.print("Connecting to ");
 Serial.println(ssid);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");

 // Start the server
 server.begin();
 Serial.println("Server started");

 // Print the IP address
 Serial.print("Use this URL to connect: ");
 Serial.print("http://");
 Serial.print(WiFi.localIP());
 Serial.println("/");

}

int16_t ax,ay,az,ax1,ay1,az1,gx,gy,gz,gx1,gy1,gz1;
int valueMotor; //vibrator motor speed 0-1023

void loop() {

 // Read accelerometer and gyroscope
 uint8_t Buf[14];
 I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);

 // Create 16 bits values from 8 bits data

 // Accelerometer
 ax=-(Buf[0]<<8 | Buf[1]);
 ay=-(Buf[2]<<8 | Buf[3]);
 az=Buf[4]<<8 | Buf[5];

 // Gyroscope
 gx=-(Buf[8]<<8 | Buf[9]);
 gy=-(Buf[10]<<8 | Buf[11]);
 gz=Buf[12]<<8 | Buf[13];  // when in "motion_mode" the vibration motor 
//is controlled by motion  
if (motor_mode==motion_mode) {  
  int v = 0;  
  //calculate motion vector 
  v=sqrt(pow(ax-ax1,2)+pow(ay-ay1,2)+pow(az-az1,2)); 
 
  // adjust vibration motor speed  
  // if motion vector > 5000 raise speed by 25
  // otherwise lower speed by 10
  // adjust these constants to your needs
  if (v > 5000) {valueMotor=valueMotor+25;} else {valueMotor=valueMotor-10;}
  
  //values must be above 500 otherwise the motor is off 
  if (valueMotor<500) {valueMotor=500;} 
  // values higher than 1023 are not supported
  if (valueMotor>1023) {valueMotor=1023;} 
  analogWrite(motorPin, valueMotor); // set motor speed

  Serial.print("v: ");
  Serial.print(v);
  Serial.print(", valueMotor: ");
  Serial.println(valueMotor);
  delay(200);

  // save values
  ax1=ax;
  ay1=ay;
  az1=az;
  gx1=gx;
  gy1=gy;
  gz1=gz;
 }

 // change vibration motor speed according to a sinus curve
 if (motor_mode==sinus_mode) {
 sinusValue=sinusValue+.01;
 delay(20);
 int sin_tmp = ((sin(sinusValue)+1)*.5*(1023-500))+500;
 Serial.println(sin_tmp);
 analogWrite(motorPin, sin_tmp);
 valueMotor=sin_tmp;
 }

 // Check if a client has connected
 WiFiClient client = server.available();
 if (!client) {
 return;
 }

 // Wait until the client sends some data
 Serial.println("new client");
 while(!client.available()){
 delay(1);
 }

 // Read the first line of the request
 String request = client.readStringUntil('\r');
 Serial.println(request);
 client.flush();

 // Match the request

 int valueLED = LOW;
 if (request.indexOf("/LED=ON") != -1) {
 digitalWrite(ledPin, HIGH);
 valueLED = HIGH;
 }
 if (request.indexOf("/LED=OFF") != -1) {
 digitalWrite(ledPin, LOW);
 valueLED = LOW;
 }

 if (request.indexOf("/MOTOR=MAX") != -1) {
 analogWrite(motorPin, 1023);
 valueMotor = 1023;
 motor_mode=max_mode;
 }
 if (request.indexOf("/MOTOR=OFF") != -1) {
 analogWrite(motorPin, 0);
 valueMotor = 0;
 motor_mode=off_mode;
 }

 if (request.indexOf("/MOTOR=SINUS") != -1) {
 motor_mode=sinus_mode;
 }

 if (request.indexOf("/MOTOR=MOTION") != -1) {
 motor_mode=motion_mode;
 valueMotor=600;
 }

 // Return the response
 client.println("HTTP/1.1 200 OK");
 client.println("Content-Type: text/html");
 client.println(""); // do not forget this one
 client.println("<!DOCTYPE HTML>");
 client.println("<html>");

 client.print("Led pin is now: ");

 if(valueLED == HIGH) {
 client.print("On");
 } else {
 client.print("Off");
 }

 client.print("Motor pin is now: ");
 client.print(valueMotor);

 client.println("");
 client.println("<a href=\"/LED=ON\"\"><button>Turn On </button></a>");
 client.println("<a href=\"/LED=OFF\"\"><button>Turn Off </button></a>");
 client.println("<a href=\"/MOTOR=MAX\"\"><button>Motor Max </button></a>");
 client.println("<a href=\"/MOTOR=OFF\"\"><button>Motor Off </button></a>");
 client.println("<a href=\"/MOTOR=SINUS\"\"><button>Motor sinus curve </button></a>");
 client.println("<a href=\"/MOTOR=MOTION\"\"><button>Motor motion controlled </button></a>");
 client.println("</html>");

 delay(1);
 Serial.println("Client disonnected");
 Serial.println("");

}

Controlling the vibrator prototype

After uploading the script above, open the serial monitor. After some time the NodeMCU will report “wifi connected”.

IOT wifi connectdNow start a browser. Use the URL which the NodeMCU reported eg. http://192.168.1.12/

If your smart phone is connected to the same Access point as your computer is, you can use your smart phone to control the prototype, too.

You can turn the LED on or off by pressing the “Turn On” and “Turn Off” buttons.

For controlling the motor you have 4 options

  • motor on
  • motor off
  • sinus curve (the motor will speed up and slow down according to a sinus curve)
  • motion controlled (more motion -> motor speeds up)

Summary

To build a vibrator prototype based on the ESP8266 MCU is very easy. You can use your Arduino IDE to upload scripts to the prototype. Then you can control the vibration motor through a browser. If you don’t want to use these external control options the vibrator prototype can be controlled by motion similar to the body interaction vibrator development board.

In this blog post series we will  explore other interesting features of the ESP8266:

  • the ESP8266 as an access point (no need for private or public access points)
  • over the air (OTA) uploading of sketches  (wireless – no USB connector needed)
  • MQTT protocol & server
  • Node-RED (visual IOT programming)
  • review of development boards for building IOT vibrators

Go to the second part of the tutorial.