Things used in this project

Hardware components:
Hexiwear docking bd
NXP Hexiwear
×1
Software apps and online services:
Workbench client evothings
Evothings Studio

Custom parts and enclosures

Hexiband
hexi-loveband.f3z

Schematics

Component Diagram
Arch

Code

index.htmlHTML
<!DOCTYPE html>

<html>

<head>

	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, user-scalable=no,
		shrink-to-fit=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />

	<title>Love Connection</title>

	<style>
		@import 'ui/css/evothings-app.css';
	</style>

	<style>
		#connectButton {
			width: 100%;
			float: left;
		}

		#disconnectButton {
			width: 49%;
			float: right;
		}

		#deviceName {
			width: 100%;
			display: block;
			-webkit-box-sizing: border-box;
			box-sizing: border-box;
		}

	</style>

	<script>

	// Redirect console.log to Evothings Workbench.
	if (window.hyper && window.hyper.log) { console.log = hyper.log }
	</script>

	<!--script src="bundle.js"></script-->
	<script src="cordova.js"></script>
	<script src="libs/jquery/jquery.js"></script>
	<script src="libs/evothings/evothings.js"></script>
	<script src="libs/evothings/ui/ui.js"></script>
	<script src="libs/bleat/bluetooth.helpers.js"></script>
	<script src="libs/bleat/api.web-bluetooth.js"></script>
	<script src="libs/bleat/adapter.evothings.js"></script>
	<script src="libs/mqttws31.js"></script>
	<script src="bundles-of-love-app.js"></script>

</head>

<body ontouchstart=""><!-- ontouchstart="" enables low-delay CSS transitions. -->
	<header>
		<button class="back" onclick="history.back()">
			<img src="ui/images/arrow-left.svg" />
		</button>
		<img class="logotype" src="ui/images/logo.svg" alt="Evothings" />
	</header>

	<h1>Love Connection</h1>

	<h2>Enter your Love Connection device</h2>

	<input id="deviceName" value="Type It Here!" type="text" />

	<button id="connectButton" class="blue">
		Connect
	</button>

	<p id="info"></p>

	<canvas id="canvas" width="300" height="150"></canvas>

</body>

</html>
bundles-of-love-app.jsJavaScript
// Using closure to avoid global name space conflicts.
;(() =>
{
'use strict';

// Timeinterval between acceleration fetch. 
const ACCELERATION_SAMPLE_PERIOD = 200; 
const MOTION_SERVICE_UUID = '2000';
const ACCELERATION_CHARACTERISTIC_UUID = '2001';


// BEWARE: These need to be edited! 
// Put In Your MQTT Credentials.
var host = 'm13.cloudmqtt.com';
var port = 1833;
var user = 'youUser';
var password = 'yourPass';


// Application object
var app = {};

// Name of the device the application will try to connect to. 
app.deviceName = 'YorDeviceName';

// The BLE GATT server.
app.gattServer = null;

// BLE objects
app.motionService = null;
app.accelerationCharacteristic = null;
app.accelerationSamples = []; 




// Initialise the application.
app.initialize = function() {

	document.addEventListener(
		'deviceready',
		app.onDeviceReady,
		false);
};

// When low level initialization is complete, this function is called.
app.onDeviceReady = function() {

	// Report status.
	app.showInfo('Enter BLE Love Connection device name and tap Connect');

	// Show the saved device name, if any.
	var name = localStorage.getItem('deviceName');
	if (name) {
		app.deviceName = name;
	}
	$('#deviceName').val(app.deviceName);

    app.pubTopic = '/love/' + device.uuid + '/evt'; // We publish to our own device topic
		app.subTopic = '/love/+/evt'; // We subscribe to all devices using "+" wildcard
		app.setupConnection(); //Make MQTT Connection
		
	// Register callback for connectButton
	$('#connectButton').click(app.onConnectButton);	
};

// Executed when the Connect/Disconnect button is pressed. 
app.onConnectButton = function() {
	
	if(app.gattServer) {
		
		app.disconnect();
	}
	else {

		app.connect();
	}
};

// Try to connect the smartphone to the GATT server.
app.connect = function() {

	// Get device name from text field.
	app.deviceName = $('#deviceName').val();

	// Save it for next time we use the app.
	localStorage.setItem('deviceName', app.deviceName);

	// Disconnect if connected.
	if (app.gattServer && app.gattServer.connected)
	{
		app.gattServer.disconnect();
		app.gattServer = null;
	}

	app.showInfo('Status: Scanning...');

	// Find and connect to device and get characteristics for LED read/write.
	bleat.requestDevice({

		filters:[{ name: app.deviceName }]
	})
	.then(device => {

		app.showInfo('Status: Found device: ' + device.name);

		// Connect to device.
		return device.gatt.connect();
	})
	.then(server => {

		app.showInfo('Status: Connected');
		
		// Save gatt server.
		app.gattServer = server;

		$('#connectButton').html('Disconnect').attr('class', 'red');

		app.timer = setInterval(function() {

			app.gattServer.getPrimaryService(MOTION_SERVICE_UUID).then(service => {
				
				app.motionService = service;
				
				return app.motionService.getCharacteristic(ACCELERATION_CHARACTERISTIC_UUID);
			})
			.then(characteristic => {

				app.accelerationCharacteristic = characteristic;
				
				return app.accelerationCharacteristic.readValue(); 
			})
			.then(accelerationBuffer => {

				// Parse acceleration variables. 
				var ax = accelerationBuffer.getInt16(0, true) / 100.0;
				var ay = accelerationBuffer.getInt16(2, true) / 100.0;
				var az = accelerationBuffer.getInt16(4, true) / 100.0;

				app.drawDiagram({ x: ax, y: ay, z: az });
				
				var args = app.build_args(ax, ay, az, new Date().valueOf());

				app.c.post(app.artikcloud, args, function(data, response) {            
					console.log(data);
				});

			})
			.catch(error => {

				app.showInfo(error);
			});

		}, ACCELERATION_SAMPLE_PERIOD);


	})
	.catch(error => {

		app.showInfo(error);
	});
};

// Disconnect smartphone from the GATT server.
app.disconnect = function() {

	// Disconnect from GATT server
	app.gattServer.disconnect();
	app.gattServer = null; 
	clearInterval(app.timer);

	// Update UI 
	app.clearDiagram();
	app.showInfo('Status: Disconnected');
	$('#connectButton').html('Connect').attr('class', 'blue');
};


// Print debug info to console and application UI.
app.showInfo = function(info) {

	document.getElementById('info').innerHTML = info;
	console.log(info);
};

app.clearDiagram = function() {

	var canvas = document.getElementById('canvas');
	var context = canvas.getContext('2d');

	// Clear diagram canvas.
	context.clearRect(0, 0, canvas.width, canvas.height);
	
	// Remove samples from array.
	app.accelerationSamples.length = 0;
};

// Draw diagram to canvas. 
app.drawDiagram = function(values) {

	var canvas = document.getElementById('canvas');
	var context = canvas.getContext('2d');

	// Add recent values.
	app.accelerationSamples.push(values);

	// Remove data points that do not fit the canvas.
	if (app.accelerationSamples.length > canvas.width) {

		app.accelerationSamples.splice(0, (app.accelerationSamples.length - canvas.width));
	}

	// Value is an accelerometer reading between -1 and 1.
	function calcDiagramY(value){

		// Return Y coordinate for this value.
		var diagramY = ((value * canvas.height) / 8) + (canvas.height / 2);
		return diagramY;
	}

	function drawLine(axis, color) {

		context.strokeStyle = color;
		context.beginPath();
		var lastDiagramY = calcDiagramY(
			app.accelerationSamples[app.accelerationSamples.length-1][axis]);
		context.moveTo(0, lastDiagramY);
		var x = 1;
		for (var i = app.accelerationSamples.length - 2; i >= 0; i--)
		{
			var y = calcDiagramY(app.accelerationSamples[i][axis]);
			context.lineTo(x, y);
			x++;
		}
		context.stroke();
	}
	
	function drawPartnerLine(axis, color, val) {

		context.strokeStyle = color;
		context.beginPath();
		context.moveTo(0, val);
		var x = 1;
		for (var i = app.accelerationSamples.length - 2; i >= 0; i--)
		{
			var y = calcDiagramY(app.accelerationSamples[i][axis]);
			context.lineTo(x, y);
			x++;
		}
		context.stroke();
	}
	

	// Clear background.
	context.clearRect(0, 0, canvas.width, canvas.height);

	// Draw lines.
	drawLine('x', '#f00');
	drawLine('y', '#0f0');
	drawLine('z', '#00f');
	
	// Publish
	if (app.connected) {
			var msg = JSON.stringify({ldata: {x:x, y:y, z:z}})
			app.publish(msg);
		}
};


app.setupConnection = function() {
  app.status("Connecting to " + host + ":" + port + " as " + device.uuid);
	app.client = new Paho.MQTT.Client(host, port, device.uuid);
	app.client.onConnectionLost = app.onConnectionLost;
	app.client.onMessageArrived = app.onMessageArrived;
	var options = {
    useSSL: true,
    onSuccess: app.onConnect,
    onFailure: app.onConnectFailure
  }
	app.client.connect(options);
}

app.publish = function(json) {
	message = new Paho.MQTT.Message(json);
	message.destinationName = app.pubTopic;
	app.client.send(message);
};

app.subscribe = function() {
	app.client.subscribe(app.subTopic);
	console.log("Subscribed: " + app.subTopic);
}

app.unsubscribe = function() {
	app.client.unsubscribe(app.subTopic);
	console.log("Unsubscribed: " + app.subTopic);
}

app.onMessageArrived = function(message) {
	var o = JSON.parse(message.payloadString);
	
	// Draw lines.
	drawPartnerLine('x', '#ff0', o.ldata.x);
	drawPartnerLine('y', '#0ff', o.ldata.y);
	drawPartnerLine('z', '#f0f', o.ldata.z);
	
}

app.onConnect = function(context) {
	app.subscribe();
	app.status("Connected!");
	app.connected = true;
}

app.onConnectFailure = function(e){
  console.log("Failed to connect: " + JSON.stringify(e));
}

app.onConnectionLost = function(responseObject) {
	app.status("Connection lost!");
	console.log("Connection lost: "+responseObject.errorMessage);
	app.connected = false;
}


// Initialize the app.
app.initialize();

})(); 

Credits

Replications

Did you replicate this project? Share it!

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Velo Bling-Bling
Advanced
  • 7,193
  • 149

Full instructions

LED lights for bicycle wheels. 16 multi color LEDs on both PCB sides. Displays images and dynamic info like speed. BLE and USB interface.

DooUcoffee Machine
Advanced
  • 1,554
  • 60

Work in progress

Internet of things in the world of coffee with Udoo - coffee machine 3.0 entirely managed by µController.

DooUcoffee Machine

Team DooUcoffee

FRDM-K82F Camera Based Parking Assistant
Advanced
  • 2,205
  • 33

Full instructions

Use Computer Vision to make a parking assistant that allows you to consistently park a car into your garage with perfect alignment.

Directional Motion-Detecting USB Web Cam Using a FRDM-K82F
Advanced
  • 2,422
  • 37

Full instructions

Use simple image processing and an image sensor to detect whether a person enters or leaves a room.

Apollo Guidance Computer Interface for Inertial Navigation
Advanced
  • 829
  • 17

A restructured approach to implementing the elegant Apollo DSKY interface for a digital inertial navigation and guidance system.

RFID Register
Advanced
  • 13,734
  • 57

Work in progress

Clock in and out of locations with Mifare RFID cards for an accurate register of movements on and off site locations.

RFID Register

Team Homeworld

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login
Feedback