Espruino:Примеры/Потоковая передача данных с Bangle.js на ПК
Потоковая передача данных с Bangle.js на ПК[1]
В этом руководстве мы расскажем, как передавать потоки данных от Bangle.js на ПК. Для этого мы воспользуемся акселерометром, а также Web Bluetooth на ПК (при помощи библиотеки Puck.js).
Более подробно об использовании Web Bluetooth с Espruino читайте в этой статье.
Во-первых, нам нужно будет настроить хостинг веб-страницы либо на своем ПК (HTTP через localhost), либо онлайн через HTTPS. Об этом немного написано в статье о Web Bluetooth.
Затем скопируйте этот код и попробуйте его в браузере.
<html>
<head>
<title>Bangle.js Accelerometer streaming</title>
</head>
<body>
<script src="https://www.puck-js.com/puck.js"></script>
<button id="btnConnect">Connect</button>
<p>X: <span class="bar"><span id="barX"></span></span></p>
<p>Y: <span class="bar"><span id="barY"></span></span></p>
<p>Z: <span class="bar"><span id="barZ"></span></span></p>
<script>
// Код для загрузки на Bangle.js.
var BANGLE_CODE = `
Bangle.on('accel',function(a) {
var d = [
"A",
Math.round(a.x*100),
Math.round(a.y*100),
Math.round(a.z*100)
];
Bluetooth.println(d.join(","));
})
`;
// Когда мы кликаем на кнопку подключения...
var connection;
document.getElementById("btnConnect").addEventListener("click", function() {
// ...отключаемся, если уже подключены.
if (connection) {
connection.close();
connection = undefined;
}
// ...подключаемся.
Puck.connect(function(c) {
if (!c) {
alert("Подключиться не удалось!");
return;
}
connection = c;
// Обрабатываем данные, пришедшие в ответ,
// и вызываем onLine() каждый раз, когда получаем строчку.
var buf = "";
connection.on("data", function(d) {
buf += d;
var l = buf.split("\n");
buf = l.pop();
l.forEach(onLine);
});
// Во-первых, выполняем сброс Bange.js.
connection.write("reset();\n", function() {
// Ждём, пока Bangle.js не выполнят сброс самих себя.
setTimeout(function() {
// Теперь загружаем на них наш код.
connection.write("\x03\x10if(1){"+BANGLE_CODE+"}\n",
function() { console.log("Готово..."); });
}, 1500);
});
});
});
// Получив строчку данных, проверяем её,
// и если она от акселерометра, обновляем её.
function onLine(line) {
console.log("ПОЛУЧЕНО:"+line);
var d = line.split(",");
if (d.length==4 && d[0]=="A") {
// Получили данные от акселерометра.
var accel = {
x : parseInt(d[1]),
y : parseInt(d[2]),
z : parseInt(d[3]),
};
// Обновляем позиции в прямоугольниках.
setBarPos("barX", accel.x);
setBarPos("barY", accel.y);
setBarPos("barZ", accel.z);
}
}
// Задаём позиции во всех прямоугольниках.
function setBarPos(id,d) {
var s = document.getElementById(id).style;
if (d>150) d=150;
if (d<-150) d=-150;
if (d>=0) {
s.left="150px";
s.width=d+"px";
} else { // меньше 0
s.left=(150+d)+"px";
s.width=(-d)+"px";
}
}
</script>
<style>
/* Добавляем стили, чтобы прямоугольники
для X, Y и Z выглядели покрасивее. */
.bar {
width : 500px;
height: 24px;
background-color : #D0D0D0;
position:relative;
display: inline-block;
}
.bar span {
width : 1px;
height: 20px;
background-color : red;
position:absolute;
display: inline-block;
left: 150px;
top: 2px;
}
</style>
</body>
</html>
Кликаем на Connect, выбираем свои Bangle.js – после этого в браузере сразу же должны начать отображаться данные от акселерометра.
Как это работает?
- Когда вы кликаете на Connect, функция Puck.connect() создает соединение с Bangle.js при помощи Web Bluetooth.
- Bangle.js выполняют сброс самих себя, после чего загружается содержимое BANGLE_CODE. То есть мы берём данные акселерометра и передаем их в браузер в формате A,x,y,z.
- При получении каждой новой строчки вызывается функция onLine() – она определяет строчки в формате A,x,y,z и соответствующим образом обновляет данные в прямоугольниках.
Вы можете добавить в код для Bangle.js побольше функций Bluetooth.println(), чтобы затем снова обнаруживать их с помощью onLine().
Подводные камни
Через соединение типа Web Bluetooth можно передавать только около 2500 байт в секунду. То есть нужно быть осторожнее и не отправлять больше данных. По умолчанию частота передачи данных акселерометра составляет 12.5 Гц, и мы округляем это значение до круглого числа, чтобы не отправлять слишком много символов.
Бонус: трехмерный куб
3D-визуализация данных акселерометра выглядит ещё более впечатляюще. Код тот же, за исключением нижней части для прямоугольников, которая заменена на код из библиотеки Three.js, работающей на технологии WebGL – она используется для рендеринга куба.
<html>
<head>
<title>Потоковая передача данных акселерометра от Bangle.js c 3D-визуализацией</title>
</head>
<body style="margin:0px">
<script src="https://www.puck-js.com/puck.js"></script>
<button id="btnConnect" style="position:absolute;left:5px;top:5px;z-index:1000">Connect</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r99/three.min.js"></script>
<script>
// Код для загрузки на Bangle.js.
var BANGLE_CODE = `
Bangle.on('accel',function(a) {
var d = [
"A",
Math.round(a.x*100),
Math.round(a.y*100),
Math.round(a.z*100)
];
Bluetooth.println(d.join(","));
})
`;
var accel = new THREE.Vector3( 0, 0, 1 );
// Когда мы кликаем на кнопку подключения...
var connection;
document.getElementById("btnConnect").addEventListener("click", function() {
// ...отключаемся, если уже подключились.
if (connection) {
connection.close();
connection = undefined;
}
// ...подключаемся.
Puck.connect(function(c) {
if (!c) {
alert("Подключиться не удалось!");
return;
}
connection = c;
// Обрабатываем данные, пришедшие в ответ,
// и вызываем onLine() каждый раз, когда получаем строчку.
var buf = "";
connection.on("data", function(d) {
buf += d;
var l = buf.split("\n");
buf = l.pop();
l.forEach(onLine);
});
// Во-первых, выполняем сброс Bangle.js.
connection.write("reset();\n", function() {
// Ждём, пока Bangle.js выполнят сброс самих себя.
setTimeout(function() {
// Теперь загружаем на них наш код.
connection.write("\x03\x10if(1){"+BANGLE_CODE+"}\n",
function() { console.log("Готово..."); });
}, 1500);
});
});
});
// Получив строчку данных, проверяем её,
// и если она от акселерометра, обновляем её.
function onLine(line) {
console.log("ПОЛУЧЕНО:"+line);
var d = line.split(",");
if (d.length==4 && d[0]=="A") {
// Мы получили данные от акселерометра.
accel.x = parseInt(d[1])/100;
accel.y = parseInt(d[2])/100;
accel.z = parseInt(d[3])/100;
render();
}
}
// Шаблон WebGL.
var scene, camera, renderer, cube;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10);
camera.position.set(0, 3.5, 5);
camera.lookAt(scene.position);
cube = new THREE.Mesh(new THREE.CubeGeometry(2, 2, 2), new THREE.MeshNormalMaterial());
scene.add(cube);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
}
function render() {
cube.lookAt(accel);
renderer.render(scene, camera);
}
init();
render();
</script>
</body>
</html>
См.также
Внешние ссылки