Skip to content

Instantly share code, notes, and snippets.

@luiseduardobrito
Created November 26, 2022 13:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luiseduardobrito/d6733a884b0e44996d1c8bec52242ace to your computer and use it in GitHub Desktop.
Save luiseduardobrito/d6733a884b0e44996d1c8bec52242ace to your computer and use it in GitHub Desktop.
<html>
<head>
<title>LYWSD02 Clock sync</title>
<meta name="viewport" content="width=480">
</head>
<body >
<h1>LYWSD02 Clock sync </h1>
<h2>Xiaomi Mijia BT4.0 Wireless Smart Electric Digital Clock Indoor & Outdoor Hygrometer Thermometer</h2>
<img src="https://imgaz3.staticbg.com/thumb/large/oaupload/banggood/images/74/DF/f05ddb02-4334-48a1-8785-39c4a5d9d9c1.jpg.webp" width="300"/>
<fieldset>
<legend>Time sync:</legend>
<label for="zone">Time zone:</label>
<input type="number" id="zone" name="zone" min="-12" max="14" value="0" /><br>
<label for="30minOffset">Add 30min offset:</label>
<input type="checkbox" id="30minOffset" name="30minOffset" /><br>
<button onclick="updateTime()">Update time</button>
</fieldset>
<fieldset>
<legend>Update unit:</legend>
<input type="radio" id="c" name="unit" value="0" checked>
<label for="c">C</label><br>
<input type="radio" id="f" name="unit" value="1">
<label for="f">F</label><br>
<button onclick="updateUnit()">Update units</button>
</fieldset>
<fieldset>
<legend>Console:</legend>
<div id="console"></div>
</fieldset>
</br></br>
<p>
<b>Based on code snippets from: </b>
<ul>
<li><a href="https://web.dev/bluetooth/" target="_blank" rel="noopener">Web.dev</a>
<li><a href="https://github.com/h4/lywsd02/blob/master/lywsd02/client.py" target="_blank" rel="noopener">lywsd02</a>
</ul>
</br>
<b>Special thanks to: </b>
<ul>
<li><a href="https://github.com/dearmash" target="_blank" rel="noopener">Harold De Armas</a> for adding C/F support
<li><a href="https://www.linkedin.com/in/mitjapugelj" target="_blank" rel="noopener">Mitja Pugelj</a> my personal hero
</ul>
</br>
</p>
<p>Use chrome developers tools for connection issues <a href="chrome://bluetooth-internals/#devices/">chrome://bluetooth-internals/#devices/</a></p>
<script>
const TIME_SERVICE = 'ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6';
const TIME = 'ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6';
const UNIT = 'ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6';
setTimeZone();
function setTimeZone() {
let offset = new Date().getTimezoneOffset();
document.getElementById('zone').value = -(parseInt(offset/60));
}
function updateTime() {
getCharecteristics(TIME_SERVICE, TIME)
.then(function (characteristic) {
log('Writting time value...')
return characteristic.writeValue(getCurrentTime());
})
.then(function () {
log('Time updated.');
})
.catch(function (error) {
log(error);
});
}
function updateUnit() {
let unitValue = parseInt(document.querySelector('input[name="unit"]:checked').value);
let charPromise = getCharecteristics(TIME_SERVICE, UNIT);
let readPromise = charPromise.then(c=>c.readValue());
Promise.all([charPromise, readPromise])
.then(function([characteristic, value]) {
let oldValue = value.getUint8(0);
log('Writting unit value (' + oldValue + ' -> ' + unitValue + ')...')
let buffer = new ArrayBuffer(1);
new DataView(buffer).setUint8(0, unitValue);
return characteristic.writeValue(buffer);
}).then(function() {
log('Unit updated');
}).catch(function (error) {
log(error);
});
}
function getCharecteristics(service, characteristic) {
if (!('bluetooth' in navigator)) {
throw 'Bluetooth API not supported.';
}
let options = {
acceptAllDevices: true,
optionalServices: [service]
};
return navigator.bluetooth.requestDevice(options)
.then(function (device) {
log('Connecting...')
return device.gatt.connect();
})
.then(function (server) {
log('Getting primary service...')
return server.getPrimaryService(service);
})
.then(function (service) {
log('Getting characteristic...')
return service.getCharacteristic(characteristic);
});
}
function log(message) {
let element = document.getElementById('console');
console.log(message);
element.innerHTML = message;
}
function getCurrentTime() {
let is30MinOffset = document.getElementById('30minOffset').checked;
let dateTime = parseInt(Date.now()/1000) + (is30MinOffset ? 30 * 60 : 0);
let buffer = new ArrayBuffer(5);
new DataView(buffer).setUint32(0, dateTime, true /* littleEndian */);
let zone = parseInt(document.getElementById('zone').value);
new DataView(buffer).setUint8(4, zone);
return buffer;
}
</script>
<style>
body {
max-width: 400px;
margin: 0 auto;
font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;
}
fieldset > * {
margin: 5px;
}
</style>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment