Visualizzazione post con etichetta IBeacon. Mostra tutti i post
Visualizzazione post con etichetta IBeacon. Mostra tutti i post
lunedì 26 marzo 2018
Estendere raggio d'azione dei beacons
Ho fatto una prova per estendere il raggio di ricezione del segnale dei Beacons Estimote. Per questo motivo ho preso un dongle USB Bluetooth 4.0 con connessione antenna SMA ed una antenna esterna direzionale della TP-LinK, anche questa dotata di connettore SMA
L'antenna e' nata per WiFi ma visto che sia WiFi che BT lavorano a 2.4 GHz non ci sono problemi
Le misure sono state fatte con un programma Python allontanandosi via via dall'antenna. In una prova di un beacon in modalita' Eddystone sono partito con un valore di RSSI di circa -46 per arrivare a circa 140 m di distanza ad un valore di RSSI -96.
venerdì 12 gennaio 2018
Estimote telemetry su PC
Questo e' un metodo per leggere i dati di telemetria dei beacon Estimote da PC senza quindi appoggiarsi ad dispositivo mobile (telefono)
Si deve installare tramite Node.js il pacchetto
npm install noble
a questo punto si puo' scaricare l'esempio estimote-telemetry.js da GitHub e modificarlo alla bisgona.
si mette in esecuzione tramite
node test.js
questo metodo e' stato testato su Centos 7 con Lenovo T430
test.js
------------------------------------
// Packest from the Estimote family (Telemetry, Connectivity, etc.) are
// broadcast as Service Data (per "ยง 1.11. The Service Data - 16 bit UUID" from
// the BLE spec), with the Service UUID 'fe9a'.
var ESTIMOTE_SERVICE_UUID = 'fe9a';
// Once you obtain the "Estimote" Service Data, here's how to check if it's
// a Telemetry packet, and if so, how to parse it.
function parseEstimoteTelemetryPacket(data) { // data is a 0-indexed byte array/buffer
// byte 0, lower 4 bits => frame type, for Telemetry it's always 2 (i.e., 0b0010)
var frameType = data.readUInt8(0) & 0b00001111;
var ESTIMOTE_FRAME_TYPE_TELEMETRY = 2;
if (frameType != ESTIMOTE_FRAME_TYPE_TELEMETRY) { return; }
// byte 0, upper 4 bits => Telemetry protocol version ("0", "1", "2", etc.)
var protocolVersion = (data.readUInt8(0) & 0b11110000) >> 4;
// this parser only understands version up to 2
// (but at the time of this commit, there's no 3 or higher anyway :wink:)
if (protocolVersion > 2) { return; }
// bytes 1, 2, 3, 4, 5, 6, 7, 8 => first half of the identifier of the beacon
var shortIdentifier = data.toString('hex', 1, 9);
// byte 9, lower 2 bits => Telemetry subframe type
// to fit all the telemetry data, we currently use two packets, "A" (i.e., "0")
// and "B" (i.e., "1")
var subFrameType = data.readUInt8(9) & 0b00000011;
var ESTIMOTE_TELEMETRY_SUBFRAME_A = 0;
var ESTIMOTE_TELEMETRY_SUBFRAME_B = 1;
// ****************
// * SUBFRAME "A" *
// ****************
if (subFrameType == ESTIMOTE_TELEMETRY_SUBFRAME_A) {
// ***** ACCELERATION
// byte 10 => acceleration RAW_VALUE on the X axis
// byte 11 => acceleration RAW_VALUE on the Y axis
// byte 12 => acceleration RAW_VALUE on the Z axis
// RAW_VALUE is a signed (two's complement) 8-bit integer
// RAW_VALUE * 2 / 127.0 = acceleration in "g-unit" (http://www.helmets.org/g.htm)
var acceleration = {
x: data.readInt8(10) * 2 / 127.0,
y: data.readInt8(11) * 2 / 127.0,
z: data.readInt8(12) * 2 / 127.0
};
// ***** MOTION STATE
// byte 15, lower 2 bits
// 0b00 ("0") when not moving, 0b01 ("1") when moving
var isMoving = (data.readUInt8(15) & 0b00000011) == 1;
// ***** MOTION STATE DURATION
// byte 13 => "previous" motion state duration
// byte 14 => "current" motion state duration
// e.g., if the beacon is currently still, "current" will state how long
// it's been still and "previous" will state how long it's previously been
// in motion before it stopped moving
//
// motion state duration is composed of two parts:
// - lower 6 bits is a NUMBER (unsigned 6-bit integer)
// - upper 2 bits is a unit:
// - 0b00 ("0") => seconds
// - 0b01 ("1") => minutes
// - 0b10 ("2") => hours
// - 0b11 ("3") => days if NUMBER is < 32
// if it's >= 32, then it's "NUMBER - 32" weeks
var parseMotionStateDuration = function(byte) {
var number = byte & 0b00111111;
var unitCode = (byte & 0b11000000) >> 6;
var unit;
if (unitCode == 0) {
unit = 'seconds';
} else if (unitCode == 1) {
unit = 'minutes';
} else if (unitCode == 2) {
unit = 'hours';
} else if (unitCode == 3 && number < 32) {
unit = 'days';
} else {
unit = 'weeks';
number = number - 32;
}
return {number: number, unit: unit};
}
var motionStateDuration = {
previous: parseMotionStateDuration(data.readUInt8(13)),
current: parseMotionStateDuration(data.readUInt8(14))
};
// ***** GPIO
// byte 15, upper 4 bits => state of GPIO pins, one bit per pin
// 0 = state "low", 1 = state "high"
var gpio = {
pin0: (data.readUInt8(15) & 0b00010000) >> 4 ? 'high' : 'low',
pin1: (data.readUInt8(15) & 0b00100000) >> 5 ? 'high' : 'low',
pin2: (data.readUInt8(15) & 0b01000000) >> 6 ? 'high' : 'low',
pin3: (data.readUInt8(15) & 0b10000000) >> 7 ? 'high' : 'low',
};
// ***** ERROR CODES
var errors;
if (protocolVersion == 2) {
// in protocol version "2"
// byte 15, bits 2 & 3
// bit 2 => firmware error
// bit 3 => clock error (likely, in beacons without Real-Time Clock, e.g.,
// Proximity Beacons, the internal clock is out of sync)
errors = {
hasFirmwareError: ((data.readUInt8(15) & 0b00000100) >> 2) == 1,
hasClockError: ((data.readUInt8(15) & 0b00001000) >> 3) == 1
};
} else if (protocolVersion == 1) {
// in protocol version "1"
// byte 16, lower 2 bits
// bit 0 => firmware error
// bit 1 => clock error
errors = {
hasFirmwareError: (data.readUInt8(16) & 0b00000001) == 1,
hasClockError: ((data.readUInt8(16) & 0b00000010) >> 1) == 1
};
} else if (protocolVersion == 0) {
// in protocol version "0", error codes are in subframe "B" instead
}
// ***** ATMOSPHERIC PRESSURE
var pressure;
if (protocolVersion == 2) {
// added in protocol version "2"
// bytes 16, 17, 18, 19 => atmospheric pressure RAW_VALUE
// RAW_VALUE is an unsigned 32-bit integer, little-endian encoding,
// i.e., least-significant byte comes first
// e.g., if bytes are 16th = 0x12, 17th = 0x34, 18th = 0x56, 19th = 0x78
// then the value is 0x78563412
// RAW_VALUE / 256.0 = atmospheric pressure in pascals (Pa)
// note that unlike what you see on the weather forecast, this value is
// not normalized to the sea level!
pressure = data.readUInt32LE(16) / 256.0;
}
return {
shortIdentifier,
frameType: 'Estimote Telemetry', subFrameType: 'A', protocolVersion,
acceleration, isMoving, motionStateDuration, pressure, gpio, errors
};
// ****************
// * SUBFRAME "B" *
// ****************
} else if (subFrameType == ESTIMOTE_TELEMETRY_SUBFRAME_B) {
// ***** MAGNETIC FIELD
// byte 10 => normalized magnetic field RAW_VALUE on the X axis
// byte 11 => normalized magnetic field RAW_VALUE on the Y axis
// byte 12 => normalized magnetic field RAW_VALUE on the Z axis
// RAW_VALUE is a signed (two's complement) 8-bit integer
// RAW_VALUE / 128.0 = normalized value, between -1 and 1
// the value will be 0 if the sensor hasn't been calibrated yet
var magneticField = {
x: data.readInt8(10) / 128.0,
y: data.readInt8(11) / 128.0,
z: data.readInt8(12) / 128.0
};
// ***** AMBIENT LIGHT
// byte 13 => ambient light level RAW_VALUE
// the RAW_VALUE byte is split into two halves
// pow(2, RAW_VALUE_UPPER_HALF) * RAW_VALUE_LOWER_HALF * 0.72 = light level in lux (lx)
var ambientLightUpper = (data.readUInt8(13) & 0b11110000) >> 4;
var ambientLightLower = data.readUInt8(13) & 0b00001111;
var ambientLightLevel = Math.pow(2, ambientLightUpper) * ambientLightLower * 0.72;
// ***** BEACON UPTIME
// byte 14 + 6 lower bits of byte 15 (i.e., 14 bits total)
// - the lower 12 bits (i.e., byte 14 + lower 4 bits of byte 15) are
// a 12-bit unsigned integer
// - the upper 2 bits (i.e., bits 4 and 5 of byte 15) denote the unit:
// 0b00 = seconds, 0b01 = minutes, 0b10 = hours, 0b11 = days
var uptimeUnitCode = (data.readUInt8(15) & 0b00110000) >> 4;
var uptimeUnit;
switch (uptimeUnitCode) {
case 0: uptimeUnit = 'seconds'; break;
case 1: uptimeUnit = 'minutes'; break;
case 2: uptimeUnit = 'hours'; break;
case 3: uptimeUnit = 'days'; break;
}
var uptime = {
number: ((data.readUInt8(15) & 0b00001111) << 8) | data.readUInt8(14),
unit: uptimeUnit
};
// ***** AMBIENT TEMPERATURE
// upper 2 bits of byte 15 + byte 16 + lower 2 bits of byte 17
// => ambient temperature RAW_VALUE, signed (two's complement) 12-bit integer
// RAW_VALUE / 16.0 = ambient temperature in degrees Celsius
var temperatureRawValue =
((data.readUInt8(17) & 0b00000011) << 10) |
(data.readUInt8(16) << 2) |
((data.readUInt8(15) & 0b11000000) >> 6);
if (temperatureRawValue > 2047) {
// JavaScript way to convert an unsigned integer to a signed one (:
temperatureRawValue = temperatureRawValue - 4096;
}
temperature = temperatureRawValue / 16.0;
// ***** BATTERY VOLTAGE
// upper 6 bits of byte 17 + byte 18 => battery voltage in mini-volts (mV)
// (unsigned 14-bit integer)
// if all bits are set to 1, it means it hasn't been measured yet
var batteryVoltage =
(data.readUInt8(18) << 6) |
((data.readUInt8(17) & 0b11111100) >> 2);
if (batteryVoltage == 0b11111111111111) { batteryVoltage = undefined; }
// ***** ERROR CODES
// byte 19, lower 2 bits
// see subframe A documentation of the error codes
// starting in protocol version 1, error codes were moved to subframe A,
// thus, you will only find them in subframe B in Telemetry protocol ver 0
var errors;
if (protocolVersion == 0) {
errors = {
hasFirmwareError: (data.readUInt8(19) & 0b00000001) == 1,
hasClockError: ((data.readUInt8(19) & 0b00000010) >> 1) == 1
};
}
// ***** BATTERY LEVEL
// byte 19 => battery level, between 0% and 100%
// if all bits are set to 1, it means it hasn't been measured yet
// added in protocol version 1
var batteryLevel;
if (protocolVersion >= 1) {
batteryLevel = data.readUInt8(19);
if (batteryLevel == 0b11111111) { batteryLevel = undefined; }
}
return {
shortIdentifier,
frameType: 'Estimote Telemetry', subFrameType: 'B', protocolVersion,
magneticField, ambientLightLevel, temperature,
uptime, batteryVoltage, batteryLevel, errors
};
}
}
// example how to scan & parse Estimote Telemetry packets with noble
var noble = require('noble');
noble.on('stateChange', function(state) {
console.log('state has changed', state);
if (state == 'poweredOn') {
var serviceUUIDs = [ESTIMOTE_SERVICE_UUID]; // Estimote Service
var allowDuplicates = true;
noble.startScanning(serviceUUIDs, allowDuplicates, function(error) {
if (error) {
console.log('error starting scanning', error);
} else {
console.log('started scanning');
}
});
}
});
noble.on('discover', function(peripheral) {
var data = peripheral.advertisement.serviceData.find(function(el) {
return el.uuid == ESTIMOTE_SERVICE_UUID;
}).data;
var telemetryPacket = parseEstimoteTelemetryPacket(data);
if (telemetryPacket) {
if (telemetryPacket['subFrameType'] == "A"){
console.log(telemetryPacket['shortIdentifier']);
//console.log(telemetryPacket['acceleration']);
console.log("AX " + telemetryPacket['acceleration']['x']);
console.log("AY " + telemetryPacket['acceleration']['y']);
console.log("AZ " + telemetryPacket['acceleration']['z']);
}
}
});
Si deve installare tramite Node.js il pacchetto
npm install noble
a questo punto si puo' scaricare l'esempio estimote-telemetry.js da GitHub e modificarlo alla bisgona.
si mette in esecuzione tramite
node test.js
questo metodo e' stato testato su Centos 7 con Lenovo T430
test.js
------------------------------------
// Packest from the Estimote family (Telemetry, Connectivity, etc.) are
// broadcast as Service Data (per "ยง 1.11. The Service Data - 16 bit UUID" from
// the BLE spec), with the Service UUID 'fe9a'.
var ESTIMOTE_SERVICE_UUID = 'fe9a';
// Once you obtain the "Estimote" Service Data, here's how to check if it's
// a Telemetry packet, and if so, how to parse it.
function parseEstimoteTelemetryPacket(data) { // data is a 0-indexed byte array/buffer
// byte 0, lower 4 bits => frame type, for Telemetry it's always 2 (i.e., 0b0010)
var frameType = data.readUInt8(0) & 0b00001111;
var ESTIMOTE_FRAME_TYPE_TELEMETRY = 2;
if (frameType != ESTIMOTE_FRAME_TYPE_TELEMETRY) { return; }
// byte 0, upper 4 bits => Telemetry protocol version ("0", "1", "2", etc.)
var protocolVersion = (data.readUInt8(0) & 0b11110000) >> 4;
// this parser only understands version up to 2
// (but at the time of this commit, there's no 3 or higher anyway :wink:)
if (protocolVersion > 2) { return; }
// bytes 1, 2, 3, 4, 5, 6, 7, 8 => first half of the identifier of the beacon
var shortIdentifier = data.toString('hex', 1, 9);
// byte 9, lower 2 bits => Telemetry subframe type
// to fit all the telemetry data, we currently use two packets, "A" (i.e., "0")
// and "B" (i.e., "1")
var subFrameType = data.readUInt8(9) & 0b00000011;
var ESTIMOTE_TELEMETRY_SUBFRAME_A = 0;
var ESTIMOTE_TELEMETRY_SUBFRAME_B = 1;
// ****************
// * SUBFRAME "A" *
// ****************
if (subFrameType == ESTIMOTE_TELEMETRY_SUBFRAME_A) {
// ***** ACCELERATION
// byte 10 => acceleration RAW_VALUE on the X axis
// byte 11 => acceleration RAW_VALUE on the Y axis
// byte 12 => acceleration RAW_VALUE on the Z axis
// RAW_VALUE is a signed (two's complement) 8-bit integer
// RAW_VALUE * 2 / 127.0 = acceleration in "g-unit" (http://www.helmets.org/g.htm)
var acceleration = {
x: data.readInt8(10) * 2 / 127.0,
y: data.readInt8(11) * 2 / 127.0,
z: data.readInt8(12) * 2 / 127.0
};
// ***** MOTION STATE
// byte 15, lower 2 bits
// 0b00 ("0") when not moving, 0b01 ("1") when moving
var isMoving = (data.readUInt8(15) & 0b00000011) == 1;
// ***** MOTION STATE DURATION
// byte 13 => "previous" motion state duration
// byte 14 => "current" motion state duration
// e.g., if the beacon is currently still, "current" will state how long
// it's been still and "previous" will state how long it's previously been
// in motion before it stopped moving
//
// motion state duration is composed of two parts:
// - lower 6 bits is a NUMBER (unsigned 6-bit integer)
// - upper 2 bits is a unit:
// - 0b00 ("0") => seconds
// - 0b01 ("1") => minutes
// - 0b10 ("2") => hours
// - 0b11 ("3") => days if NUMBER is < 32
// if it's >= 32, then it's "NUMBER - 32" weeks
var parseMotionStateDuration = function(byte) {
var number = byte & 0b00111111;
var unitCode = (byte & 0b11000000) >> 6;
var unit;
if (unitCode == 0) {
unit = 'seconds';
} else if (unitCode == 1) {
unit = 'minutes';
} else if (unitCode == 2) {
unit = 'hours';
} else if (unitCode == 3 && number < 32) {
unit = 'days';
} else {
unit = 'weeks';
number = number - 32;
}
return {number: number, unit: unit};
}
var motionStateDuration = {
previous: parseMotionStateDuration(data.readUInt8(13)),
current: parseMotionStateDuration(data.readUInt8(14))
};
// ***** GPIO
// byte 15, upper 4 bits => state of GPIO pins, one bit per pin
// 0 = state "low", 1 = state "high"
var gpio = {
pin0: (data.readUInt8(15) & 0b00010000) >> 4 ? 'high' : 'low',
pin1: (data.readUInt8(15) & 0b00100000) >> 5 ? 'high' : 'low',
pin2: (data.readUInt8(15) & 0b01000000) >> 6 ? 'high' : 'low',
pin3: (data.readUInt8(15) & 0b10000000) >> 7 ? 'high' : 'low',
};
// ***** ERROR CODES
var errors;
if (protocolVersion == 2) {
// in protocol version "2"
// byte 15, bits 2 & 3
// bit 2 => firmware error
// bit 3 => clock error (likely, in beacons without Real-Time Clock, e.g.,
// Proximity Beacons, the internal clock is out of sync)
errors = {
hasFirmwareError: ((data.readUInt8(15) & 0b00000100) >> 2) == 1,
hasClockError: ((data.readUInt8(15) & 0b00001000) >> 3) == 1
};
} else if (protocolVersion == 1) {
// in protocol version "1"
// byte 16, lower 2 bits
// bit 0 => firmware error
// bit 1 => clock error
errors = {
hasFirmwareError: (data.readUInt8(16) & 0b00000001) == 1,
hasClockError: ((data.readUInt8(16) & 0b00000010) >> 1) == 1
};
} else if (protocolVersion == 0) {
// in protocol version "0", error codes are in subframe "B" instead
}
// ***** ATMOSPHERIC PRESSURE
var pressure;
if (protocolVersion == 2) {
// added in protocol version "2"
// bytes 16, 17, 18, 19 => atmospheric pressure RAW_VALUE
// RAW_VALUE is an unsigned 32-bit integer, little-endian encoding,
// i.e., least-significant byte comes first
// e.g., if bytes are 16th = 0x12, 17th = 0x34, 18th = 0x56, 19th = 0x78
// then the value is 0x78563412
// RAW_VALUE / 256.0 = atmospheric pressure in pascals (Pa)
// note that unlike what you see on the weather forecast, this value is
// not normalized to the sea level!
pressure = data.readUInt32LE(16) / 256.0;
}
return {
shortIdentifier,
frameType: 'Estimote Telemetry', subFrameType: 'A', protocolVersion,
acceleration, isMoving, motionStateDuration, pressure, gpio, errors
};
// ****************
// * SUBFRAME "B" *
// ****************
} else if (subFrameType == ESTIMOTE_TELEMETRY_SUBFRAME_B) {
// ***** MAGNETIC FIELD
// byte 10 => normalized magnetic field RAW_VALUE on the X axis
// byte 11 => normalized magnetic field RAW_VALUE on the Y axis
// byte 12 => normalized magnetic field RAW_VALUE on the Z axis
// RAW_VALUE is a signed (two's complement) 8-bit integer
// RAW_VALUE / 128.0 = normalized value, between -1 and 1
// the value will be 0 if the sensor hasn't been calibrated yet
var magneticField = {
x: data.readInt8(10) / 128.0,
y: data.readInt8(11) / 128.0,
z: data.readInt8(12) / 128.0
};
// ***** AMBIENT LIGHT
// byte 13 => ambient light level RAW_VALUE
// the RAW_VALUE byte is split into two halves
// pow(2, RAW_VALUE_UPPER_HALF) * RAW_VALUE_LOWER_HALF * 0.72 = light level in lux (lx)
var ambientLightUpper = (data.readUInt8(13) & 0b11110000) >> 4;
var ambientLightLower = data.readUInt8(13) & 0b00001111;
var ambientLightLevel = Math.pow(2, ambientLightUpper) * ambientLightLower * 0.72;
// ***** BEACON UPTIME
// byte 14 + 6 lower bits of byte 15 (i.e., 14 bits total)
// - the lower 12 bits (i.e., byte 14 + lower 4 bits of byte 15) are
// a 12-bit unsigned integer
// - the upper 2 bits (i.e., bits 4 and 5 of byte 15) denote the unit:
// 0b00 = seconds, 0b01 = minutes, 0b10 = hours, 0b11 = days
var uptimeUnitCode = (data.readUInt8(15) & 0b00110000) >> 4;
var uptimeUnit;
switch (uptimeUnitCode) {
case 0: uptimeUnit = 'seconds'; break;
case 1: uptimeUnit = 'minutes'; break;
case 2: uptimeUnit = 'hours'; break;
case 3: uptimeUnit = 'days'; break;
}
var uptime = {
number: ((data.readUInt8(15) & 0b00001111) << 8) | data.readUInt8(14),
unit: uptimeUnit
};
// ***** AMBIENT TEMPERATURE
// upper 2 bits of byte 15 + byte 16 + lower 2 bits of byte 17
// => ambient temperature RAW_VALUE, signed (two's complement) 12-bit integer
// RAW_VALUE / 16.0 = ambient temperature in degrees Celsius
var temperatureRawValue =
((data.readUInt8(17) & 0b00000011) << 10) |
(data.readUInt8(16) << 2) |
((data.readUInt8(15) & 0b11000000) >> 6);
if (temperatureRawValue > 2047) {
// JavaScript way to convert an unsigned integer to a signed one (:
temperatureRawValue = temperatureRawValue - 4096;
}
temperature = temperatureRawValue / 16.0;
// ***** BATTERY VOLTAGE
// upper 6 bits of byte 17 + byte 18 => battery voltage in mini-volts (mV)
// (unsigned 14-bit integer)
// if all bits are set to 1, it means it hasn't been measured yet
var batteryVoltage =
(data.readUInt8(18) << 6) |
((data.readUInt8(17) & 0b11111100) >> 2);
if (batteryVoltage == 0b11111111111111) { batteryVoltage = undefined; }
// ***** ERROR CODES
// byte 19, lower 2 bits
// see subframe A documentation of the error codes
// starting in protocol version 1, error codes were moved to subframe A,
// thus, you will only find them in subframe B in Telemetry protocol ver 0
var errors;
if (protocolVersion == 0) {
errors = {
hasFirmwareError: (data.readUInt8(19) & 0b00000001) == 1,
hasClockError: ((data.readUInt8(19) & 0b00000010) >> 1) == 1
};
}
// ***** BATTERY LEVEL
// byte 19 => battery level, between 0% and 100%
// if all bits are set to 1, it means it hasn't been measured yet
// added in protocol version 1
var batteryLevel;
if (protocolVersion >= 1) {
batteryLevel = data.readUInt8(19);
if (batteryLevel == 0b11111111) { batteryLevel = undefined; }
}
return {
shortIdentifier,
frameType: 'Estimote Telemetry', subFrameType: 'B', protocolVersion,
magneticField, ambientLightLevel, temperature,
uptime, batteryVoltage, batteryLevel, errors
};
}
}
// example how to scan & parse Estimote Telemetry packets with noble
var noble = require('noble');
noble.on('stateChange', function(state) {
console.log('state has changed', state);
if (state == 'poweredOn') {
var serviceUUIDs = [ESTIMOTE_SERVICE_UUID]; // Estimote Service
var allowDuplicates = true;
noble.startScanning(serviceUUIDs, allowDuplicates, function(error) {
if (error) {
console.log('error starting scanning', error);
} else {
console.log('started scanning');
}
});
}
});
noble.on('discover', function(peripheral) {
var data = peripheral.advertisement.serviceData.find(function(el) {
return el.uuid == ESTIMOTE_SERVICE_UUID;
}).data;
var telemetryPacket = parseEstimoteTelemetryPacket(data);
if (telemetryPacket) {
if (telemetryPacket['subFrameType'] == "A"){
console.log(telemetryPacket['shortIdentifier']);
//console.log(telemetryPacket['acceleration']);
console.log("AX " + telemetryPacket['acceleration']['x']);
console.log("AY " + telemetryPacket['acceleration']['y']);
console.log("AZ " + telemetryPacket['acceleration']['z']);
}
}
});
lunedì 19 ottobre 2015
DIY Homekit con Arduino
Dopo un primo esperimento con DIY HomeKit (a questo post) non ero particolarmente contento perche' comunque i costi di Raspberry e la gestione in generale non erano ottimali ed ho provato a replicare la cosa su Arduino
Per il modulo Bluetooth ho usato un modulo Bluetooth LE HM-10 del costo di circa 5 euro (qui). Attenzione, non tutti i moduli BT per Arduino supportano BT4 LE. Il modulo riporta sul retro la scritta AC-BT-V4 ed al comando AT+NAME? risponde con HMSoft
Il modulo si comanda tramite stringhe AT (per l'elenco completo dei comandi si puo' leggere qui il manuale di istruzioni)
Cio' che interessa e' la sequenza di comando
AT+ROLE1
AT+IMME1
AT+DISI?
all'ultimo comando il dispositivo risponde in questo modo
---------------------------------------------------------
OK+DISIS
OK+DISC:4C000215:B9407F30F5F8466EAFF925556B57FE6D:DB2A91AEB6:D81691AEDB2A:-084
OK+DISCE
---------------------------------------------------------
Sono stati avvistati 3 beacons (due Estimote ed un Eddystone riconoscibile da tutti zeri perche' il protocollo non e' riconosciuto)
Prendendo la riga evidenziata in giallo
iBeacon ID = B9407F30F5F8466EAFF925556B57FE6D
Major = 7188
Minor = 4DF6
Measured power (182 decimale) =B6
Mac Address = F1A84DF67188
RSSI = -86
Passando quindi ad Arduino
I collegamenti sono banali (verra' usata la Seriale Software di Arduino)
BT VCC +3.3V Arduino
BT GND GND Arduino
BT RXD D2 Arduino
BT TXD D3 Arduino
Nello sketch seguente se viene individuato il beacon con minor AEB6 viene attivato il pin D13 in modo da aprire il contatto su un rele'; se per piu' di 50 secondi non viene piu' messo in lista il beacon con minor AEB6 il pin D13 va Low e si chiude il rele (il codice si commenta da solo)
--------------------------------------------------------------------------------------
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);
char risposta[115];
int conta;
int rele = 13;
long tempo;
void setup()
{
Serial.begin(9600);
mySerial.begin(9600);
mySerial.write("AT+ROLE1");
mySerial.write("AT+IMME1");
if (mySerial.available())
{
while (mySerial.available()>0){
}
}
pinMode(rele, OUTPUT);
tempo = 0;
}
void loop()
{
mySerial.write("AT+DISI?");
if (mySerial.available())
{
conta = 0;
while (mySerial.available()>0){
risposta[conta] = mySerial.read();
conta = conta + 1;
}
}
if ((risposta[56] == 'A') && (risposta[57] == 'E') && (risposta[58] == 'B') && (risposta[59] == '6'))
{
//Serial.println("ATTENZIONE");
digitalWrite(rele, HIGH);
tempo = 0;
}
delay(500);
tempo = tempo + 1;
if (tempo > 100)
{
digitalWrite(rele, LOW);
tempo = 101;
}
}
Per il modulo Bluetooth ho usato un modulo Bluetooth LE HM-10 del costo di circa 5 euro (qui). Attenzione, non tutti i moduli BT per Arduino supportano BT4 LE. Il modulo riporta sul retro la scritta AC-BT-V4 ed al comando AT+NAME? risponde con HMSoft
Il modulo si comanda tramite stringhe AT (per l'elenco completo dei comandi si puo' leggere qui il manuale di istruzioni)
Cio' che interessa e' la sequenza di comando
AT+ROLE1
AT+IMME1
AT+DISI?
all'ultimo comando il dispositivo risponde in questo modo
---------------------------------------------------------
OK+DISIS
OK+DISC:4C000215:B9407F30F5F8466EAFF925556B57FE6D:71884DF6B6:F1A84DF67188:-086
OK+DISC:00000000:00000000000000000000000000000000:0000000000:C493974F69E2:-084OK+DISC:4C000215:B9407F30F5F8466EAFF925556B57FE6D:DB2A91AEB6:D81691AEDB2A:-084
OK+DISCE
---------------------------------------------------------
Sono stati avvistati 3 beacons (due Estimote ed un Eddystone riconoscibile da tutti zeri perche' il protocollo non e' riconosciuto)
Prendendo la riga evidenziata in giallo
iBeacon ID = B9407F30F5F8466EAFF925556B57FE6D
Major = 7188
Minor = 4DF6
Measured power (182 decimale) =B6
Mac Address = F1A84DF67188
RSSI = -86
Passando quindi ad Arduino
I collegamenti sono banali (verra' usata la Seriale Software di Arduino)
BT VCC +3.3V Arduino
BT GND GND Arduino
BT RXD D2 Arduino
BT TXD D3 Arduino
Nello sketch seguente se viene individuato il beacon con minor AEB6 viene attivato il pin D13 in modo da aprire il contatto su un rele'; se per piu' di 50 secondi non viene piu' messo in lista il beacon con minor AEB6 il pin D13 va Low e si chiude il rele (il codice si commenta da solo)
--------------------------------------------------------------------------------------
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);
char risposta[115];
int conta;
int rele = 13;
long tempo;
void setup()
{
Serial.begin(9600);
mySerial.begin(9600);
mySerial.write("AT+ROLE1");
mySerial.write("AT+IMME1");
if (mySerial.available())
{
while (mySerial.available()>0){
}
}
pinMode(rele, OUTPUT);
tempo = 0;
}
void loop()
{
mySerial.write("AT+DISI?");
if (mySerial.available())
{
conta = 0;
while (mySerial.available()>0){
risposta[conta] = mySerial.read();
conta = conta + 1;
}
}
if ((risposta[56] == 'A') && (risposta[57] == 'E') && (risposta[58] == 'B') && (risposta[59] == '6'))
{
//Serial.println("ATTENZIONE");
digitalWrite(rele, HIGH);
tempo = 0;
}
delay(500);
tempo = tempo + 1;
if (tempo > 100)
{
digitalWrite(rele, LOW);
tempo = 101;
}
}
venerdì 28 agosto 2015
EddyStone Beacons
Eddystone e' una specifica per beacons a formato aperto (che si differenzia da IBeacons di marchio Apple) recentemente uscita e sponsorizzata da Google
Non tutti i beacon sono in grado di trasmettere in formato Eddystone ma quelli riprogrammabili (e di marca) come Radius ed Estimote possono essere trasformati in modalita' Eddystone
Beacon Estimote in modalita' Eddystone |
C'e' da dire che le due modalita' sono esclusive (od il beacon trasmette in modalita' IBeacon od in EddyStone) e che la durata stimata delle batterie su Eddystone e' inferiore a quella IBeacon
C'e' pero' da osservare un paio di aspetti importanti:
1) Eddystone permette di trasmettere, oltre all'UUID come IBeacon, anche stringhe di testo. In questo modo si puo' evitare l'utilizzo di un server esterno se per esempio si vuole pubblicizzare un prodotto in una vetrina (per esempio) . Si programma il beacon per puntare ad un link sullo store invece che ad un proprio server che legge l'UUID, interroga il database e fornisce il link del prodotto.
2) il formato e' libero e quindi meno soggetto alle guerre tra marchi (in questo modo verra' sdoganato l'uso dei beacon anche su Android)
Google ha pubblicato gli esempi sull'utilizzo (sia per Android che IOS) a questo link.
Oltre al protocollo Eddystone Google fornisce anche una infrastruttura cloud per gestire una eventuale flotta di beacons (un po' sullo stile di cio' che gia' offre Estimte) tramite le Proximity API
ps: alla data attuale l'applicazione Estimote per IOS non gestisce il protocollo Eddystone e non riconosce il broadcast da questi dispositivi. L'applicazione Estimote per Android invece funziona perfettamente con il nuovo formato
martedì 28 aprile 2015
Schermare beacon
Lavorando con diversi beacon e' piuttosto fastidioso quando interferiscono tra di loro all'interno dell'ufficio
Un sistema banale e' quello di avvolgere i trasmettitori nella carta argentata per uso alimentare (piu' di una volta, un solo giro non e' garanzia di schermatura), altrimenti possono essere messi dentro un forno a microonde
venerdì 26 dicembre 2014
IBeacon ed IOS8
In estate avevo scritto una piccola applicazione per IBeacon
E' passata l'estate e l'autunno ma sono rimasto fedele a IOS 7 e OS X 10.9 perche' i sistemi operativi troppo recenti sono sempre fonti di problemi; in questi giorni mi sono pero' convinto a passare ad IOS 8.1.2 sul telefono ed a OSX 10.10 sul portatile
La sorpresa e' venuta quando sono arrivato a compilare ed eseguire il codice per IBeacon che precedemente funzionava perfettamente. Nonostante non ci fossero errori di compilazione ne' errori di esecuzione il programma semplicemente aveva smesso di riconoscere i beacons vicini
Dopo un paio di giorni a battere il capo sul muro sono arrivato su questo link in cui si segnala che con l'arrivo di IOS 8 si devono aggiungere un paio di stringhe un info.plist del progetto
-----------------------------------------
<key>NSLocationAlwaysUsageDescription</key>
E' passata l'estate e l'autunno ma sono rimasto fedele a IOS 7 e OS X 10.9 perche' i sistemi operativi troppo recenti sono sempre fonti di problemi; in questi giorni mi sono pero' convinto a passare ad IOS 8.1.2 sul telefono ed a OSX 10.10 sul portatile
La sorpresa e' venuta quando sono arrivato a compilare ed eseguire il codice per IBeacon che precedemente funzionava perfettamente. Nonostante non ci fossero errori di compilazione ne' errori di esecuzione il programma semplicemente aveva smesso di riconoscere i beacons vicini
Dopo un paio di giorni a battere il capo sul muro sono arrivato su questo link in cui si segnala che con l'arrivo di IOS 8 si devono aggiungere un paio di stringhe un info.plist del progetto
-----------------------------------------
<key>NSLocationAlwaysUsageDescription</key>
<string>Messaggio Utente</string>
-----------------------------------------
oppure
-----------------------------------------
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your message goes here</string>
oppure
-----------------------------------------
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your message goes here</string>
-----------------------------------------
effettuate queste modifiche il programma ha ricominciato a funzionare (e' in questi momenti che amo la programmazione :<<<<
effettuate queste modifiche il programma ha ricominciato a funzionare (e' in questi momenti che amo la programmazione :<<<<
venerdì 5 dicembre 2014
Estimote Virtual Beacon
Nell'applicazione Estimote per cellulari e' disponibile anche la funzione Virtual Beacon
Il problema e' che, usando gli esempi di Estimote, si riescono a visualizzare i beacon fisici e non il virtual beacon
il problema risiede nel fatto che i beacon fisici Estimote hanno un uuid B9407F30-F5F8-466E-AFF9-25556B57FE6D mentre i virtual beacon hanno un uuid 8492E75F-4FD6-469D-B132-043FE94921D8
Modificando questo parametro e' possibile usare i virtual beacon per gli esempi di Estimote
venerdì 14 novembre 2014
Estimote RSSI
A seguito del precedente post ho ripetuto la prova anche con un Estimote
Valore medio RSSI: -67.1
St.Deviation : 1.95
Scarto massimo positivo : 2.15
Scarto massimo negativo : -3.84
Valore medio RSSI: -67.1
St.Deviation : 1.95
Scarto massimo positivo : 2.15
Scarto massimo negativo : -3.84
mercoledì 5 novembre 2014
martedì 4 novembre 2014
Trilaterazione 2D con beacon
L'algoritmo di trilaterazione e' una tecnica che permette di individuare la posizione di un punto sconosciuto conosciuto le distanze dello stesso da punti quotati. La versione 3D e' alla base del posizionamento GPS ma quello che mi interessa e' la sua versione 2D per cercare di poter fare posizionamento indoor mediante antenne WiFi o beacons
Su questo argomento esiste una vasta letterature ingegneristica con risultati che vanno da ottimi a pessimi.
Nell'immagine viene riportato il metodo di calcolo (non ricordo la fonte)
Per semplicita' uno dei punti di riferimento e' in (0,0) mentre un altro e' sull'asse X (d,0). Il terzo punto e' in (i,j) mentre le distanze del punto incognito sono rispettivamente R1, R2 ed R3
Per la prova ho usato tre beacons. Ho quindi realizzato una curva di taratura (per quanto possibile) che mi convertisse il valore di RSSI in metri
La prova e' stata effettuata creando una griglia regolare di 5x5 m e 3x3 m ed effettuando misure su alcuni nodi. In blu sono riportati i valori reali ed in rosso le posizioni calcolate
Importante: per ogni posizione e' stato preso il valore istantaneo di RSSI senza effettuare medie di lunga durata perche' il tentativo era di tracciare il percorso di una persona in movimento
Risultati griglia 5x5 |
Risultati griglia 3x3 m |
E' evidente che la prova ha avuto un esito decisamente negativo. L'algoritmo di calcolo di trilaterazione funziona, cio' che difetta e' la stabilita' del segnale dei beacons e l'impossibilita' di avere una legge affidabile per convertire i valori di RSSI in distanze
lunedì 3 novembre 2014
RSSI vs Distanza per CC2540/CC2541/Gimbal10
Giusto per prova ho messo in grafico i valori di RSSI e distanza per vedere se si trova una legge semplice per calcolare la distanza (non mi interessa se la legge di correlazione ha un senso fisico, solo che abbia un buon fit)
I valori sono mediati su molte misure (altrimenti si osservano le fluttuazioni del post precedente)
Come indicazione generale si riesce a calcolare discretamente la distanza per valori inferiori al 1.5 m. CC2540 e' quello per cui i valori di RSSI vanno rapidamente a -100 e quindi sono indicati solo per una prossimita' molto stretta
I valori sono mediati su molte misure (altrimenti si osservano le fluttuazioni del post precedente)
Come indicazione generale si riesce a calcolare discretamente la distanza per valori inferiori al 1.5 m. CC2540 e' quello per cui i valori di RSSI vanno rapidamente a -100 e quindi sono indicati solo per una prossimita' molto stretta
CC2540 vs CC2541 cc Gimbal
Avendo tre modelli di Beacons ho provato a vedere quali sono le differenze principali
Per rendere comparabili i risultati ho effettuato una serie di misure di RSSI ad una distanza di 1 m con un medesimo telefono (Iphone 4S) ed utilizzando le applicazioni ufficiali dei costruttori
I tre processori sono il TI CC2540 (TI vecchio), TI 2541 (TI nuovo) e Gimbals serie 10
TI CC2540
valore medio : -84.6
st. dev : 1.78
differenza massima positiva : 2.4
differenza massima negativa : -3.6
TI CC2541
valore medio : -73.2
st. dev : 1.77
differenza massima positiva : 2.8
differenza massima negativa : -3.2
Gimbal serie 10
valore medio : -90.6
st. dev : 1.78
differenza massima positiva : 3.3
differenza massima negativa : -4.6
In conclusione :
1) tutti i beacon esaminati hanno un valore simile di standard deviation per cui non esiste un vincitore
2) il valore di RSSI per tutti e' molto variabile, troppo per fare un posizionamento preciso
Per rendere comparabili i risultati ho effettuato una serie di misure di RSSI ad una distanza di 1 m con un medesimo telefono (Iphone 4S) ed utilizzando le applicazioni ufficiali dei costruttori
Grafico delle misure |
valore medio : -84.6
st. dev : 1.78
differenza massima positiva : 2.4
differenza massima negativa : -3.6
TI CC2541
valore medio : -73.2
st. dev : 1.77
differenza massima positiva : 2.8
differenza massima negativa : -3.2
Gimbal serie 10
valore medio : -90.6
st. dev : 1.78
differenza massima positiva : 3.3
differenza massima negativa : -4.6
In conclusione :
1) tutti i beacon esaminati hanno un valore simile di standard deviation per cui non esiste un vincitore
2) il valore di RSSI per tutti e' molto variabile, troppo per fare un posizionamento preciso
venerdì 31 ottobre 2014
Gimbal beacons
Aggiornamento
Con alcune app i beacon Gimbal sono visibili ma cambiano continuamente MAC Address per cui la lista continua ad aggiornarsi scoprendo sempre nuovi beacon (in realta' e' sempre il solito che aggiorna il proprio identificativo di basso livello)
Cio' comporta problemi su Android. Secondo quanto riportato da questo post di Radius Network (una ditta concorrente) dopo circa 40 minuti di utilizzo una applicazione Android va in crash a causa del numero limitato della lista di MAC Address che Android riesce a gestire
----------------------------------------
Grazie ad una simpatica iniziativa per gli sviluppatori (spediscono un kit gratuito anche all'estero...nonostante che sia indicato solo per gli USA) sono entrato in possesso di tre beacons Gimbal ovvero Qualcomm
Rispetto agli altri beacon testati basati sul TI CC2540 questi sono basati su processori proprietari della Qualcomm e sono decisamente molto meglio ingegnerizzati e miniturizzati (lo spazio e' quasi totalmente occupato dalla batteria CR2032)
Una prima differenza rispetto agli altri beacon testati e' che questi non vengono segnalati dai programmi basati sul uuid-major-minor. In pratica ogni beacon ha un proprio codice (4 caratteri - 5 caratteri) che deve essere comunicato a Gimbal per l'attivazione; in seguito i beacon solo visibili medianti le applicazione sviluppate con l'SDK di Gimbal (IOS e Android-Beta) ma non con altri software
Con il beacon posto vicino al telefono l'RSSI e' di -40, portandolo a circa ad oltre 3 m scende circa -80. Riportando velocemente in grafico
Il segnale risulta molto stabile (prova effettuata ad un 1 metro di distanza tra beacon ed IPhone) con una standard deviation del valore di RSSI di circa 0.6 unita'
Su Android le cose sono leggermente differenti con un valore di standard deviation di 1.2 unita'. Non male vista la precedente esperienza con i Texas Instruments
Con alcune app i beacon Gimbal sono visibili ma cambiano continuamente MAC Address per cui la lista continua ad aggiornarsi scoprendo sempre nuovi beacon (in realta' e' sempre il solito che aggiorna il proprio identificativo di basso livello)
Cio' comporta problemi su Android. Secondo quanto riportato da questo post di Radius Network (una ditta concorrente) dopo circa 40 minuti di utilizzo una applicazione Android va in crash a causa del numero limitato della lista di MAC Address che Android riesce a gestire
----------------------------------------
Grazie ad una simpatica iniziativa per gli sviluppatori (spediscono un kit gratuito anche all'estero...nonostante che sia indicato solo per gli USA) sono entrato in possesso di tre beacons Gimbal ovvero Qualcomm
Rispetto agli altri beacon testati basati sul TI CC2540 questi sono basati su processori proprietari della Qualcomm e sono decisamente molto meglio ingegnerizzati e miniturizzati (lo spazio e' quasi totalmente occupato dalla batteria CR2032)
Una prima differenza rispetto agli altri beacon testati e' che questi non vengono segnalati dai programmi basati sul uuid-major-minor. In pratica ogni beacon ha un proprio codice (4 caratteri - 5 caratteri) che deve essere comunicato a Gimbal per l'attivazione; in seguito i beacon solo visibili medianti le applicazione sviluppate con l'SDK di Gimbal (IOS e Android-Beta) ma non con altri software
Con il beacon posto vicino al telefono l'RSSI e' di -40, portandolo a circa ad oltre 3 m scende circa -80. Riportando velocemente in grafico
Il segnale risulta molto stabile (prova effettuata ad un 1 metro di distanza tra beacon ed IPhone) con una standard deviation del valore di RSSI di circa 0.6 unita'
Su Android le cose sono leggermente differenti con un valore di standard deviation di 1.2 unita'. Non male vista la precedente esperienza con i Texas Instruments
venerdì 24 ottobre 2014
Bluetooth LE su MacBook Late 2009
Con il nuovo OsX prende ancora piu' importanza nel mondo Mac la presenza di Bluetooth 4
Avendo un MacBook Pro Late 2009 non e' montato di serie un chip Bluetooth LE.
Ho provato quindi a recuperare il dongle gia' usato per Linux visto sul precedente post
Con sorpresa il chip Broadcom BCM20702 viene riconosciuto da MacOs X 10.9.5 senza problemi.
Per rendere operativo il dongle si puo' usare il programma BeaconScanner (link) per registrare la presenza di beacon nelle vicinanze al portatile ed il programma BeaconOsX (link) per trasformare il MacBook in un beacon
Avendo un MacBook Pro Late 2009 non e' montato di serie un chip Bluetooth LE.
Ho provato quindi a recuperare il dongle gia' usato per Linux visto sul precedente post
Con sorpresa il chip Broadcom BCM20702 viene riconosciuto da MacOs X 10.9.5 senza problemi.
Per rendere operativo il dongle si puo' usare il programma BeaconScanner (link) per registrare la presenza di beacon nelle vicinanze al portatile ed il programma BeaconOsX (link) per trasformare il MacBook in un beacon
lunedì 25 agosto 2014
Potenza del segnale di CC2541
L'integrato Texas Instruments CC2541 su cui si basano alcuni beacon permette di modificare la potenza di trasmissione da +4 dBm a -23 dBm. Cio' consente di aumentare o diminuire il proprio raggio d'azione
Nell'applicazione che uso i valori di potenza non impostati a 4 valori prefissati
0 dBm : potenza standard
4 dBm : circa il doppio della potenza standard
-6 dBm : un quarto della potenza standard
-23 dBm : un ventesimo della potenza standard
Per vedere se effettivamente le modifiche influenzano il raggio d'azione del beacon ho provato a plottare la potenza contro il valore di rssi (facendo una media e la deviazione standard di una serie di dati a causa della instabilita' intrinseca del segnale). La prova e' stata eseguita mantenendo beacon e telefono a distanza fissa per tutto il tempo
Come si vede dal grafico i casi 0dBm e +4dBm sono praticamente non distinguibili, nel caso di -6dBm il valore di rssi e' di qualita' inferiore a causa della diminuzione del segnale. Quando la potenza del beacon passa a -23dBm il valore di rssi e' praticamente fisso a 95 ovvero il telefono e' praticamente fuori al raggio d'azione del beacon e legge solo un valore di fondo scala
martedì 22 luglio 2014
AndroidIBeaconLibrary e' morta??
Un po' di tempo fa avevo indicato come sviluppare applicazione IBeacon su Android mediante l'utilizzo della libreria AndroidIBeaconLibrary di Radius
In questi giorni avevo bisogno di rimettere mano alla libreria e con mia grande sorpresa il progetto e' scomparso dal sito di Radius Network e la pagina GitHub mostra un laconico messaggio
Per avere un po' di idee sul motivo di una cosi' repentina rimozione si puo' leggere questo post
Ma e' veramente morta questa libreria??
La cosa divertente e' che su GitHub sono presenti ancora tutti i commit per cui e' sufficiente effettuare un fork del progetto (legale in base alla licenza Apache) mediante l'apposito pulsante
per copiare tutta la storia di commit nella propria pagina GitHub.
A questo punto si puo' cliccare il pulsante Clone On Desktop per copiare tutta la storia dei commit anche sul proprio client
In questi giorni avevo bisogno di rimettere mano alla libreria e con mia grande sorpresa il progetto e' scomparso dal sito di Radius Network e la pagina GitHub mostra un laconico messaggio
Per avere un po' di idee sul motivo di una cosi' repentina rimozione si puo' leggere questo post
Ma e' veramente morta questa libreria??
La cosa divertente e' che su GitHub sono presenti ancora tutti i commit per cui e' sufficiente effettuare un fork del progetto (legale in base alla licenza Apache) mediante l'apposito pulsante
per copiare tutta la storia di commit nella propria pagina GitHub.
A questo punto si puo' cliccare il pulsante Clone On Desktop per copiare tutta la storia dei commit anche sul proprio client
con il comando Revert si puo' quindi generare una qualsiasi release della libreria
Ancora piu' semplice, visto che la rete nasconde ma difficilmente cancella, sui server di Amazon sono disponibili ancora i file tar.gz della versione per Eclipse
Per rendere le cose ancora piu' semplici ho copiato le ultime tre versioni sul mio Google Drive (tutte per uso con Eclipse)
martedì 8 luglio 2014
IBeacon ed aggiornamento IOS 7.1.2 su Iphone 4S
Sviluppando per beacon su IOS mi sono trovato di fronte ad una cosa piuttosto strana
Il medesimo codice che girava correttamente su un Iphone 5S si rifiutava di funzionare su Iphone 4S a parita' di IOS installato
Con l'uscita dell'aggiornamento ad IOS 7.1.2 tutto si e' risolto senza modificare nessuna parte del codice dell'applicazione
lunedì 7 luglio 2014
Beacon su IOS
A seguito delle prove effettuate in questo post ed in questo post (usando in entrambi i casi un telefono Moto G con Android e librerie Radius) mi sono convertito ad IOS ed ho ripetuto l'esperienza usando un IPhone 4S con le medesime antenne usate in precedenza e le API di IOS
non ho ancora capito bene il motivo ma sembra che il segnale risulta nettamente piu' stabile su IOS che su Android (hardware o software???)
da notare che al contrario di Android su IOS vengono segnalati come valori negativi le fallite acquisizioni
il codice impiegato per misurare il segnale e' riportato in seguito (ripreso da questo link dall'esempio Art Gallery)
#import "ViewController.h"
#define ESTIMOTE_PROXIMITY_UUID [[NSUUID alloc] initWithUUIDString:@"4506F9C7-00F9-C206-C12C-C2F9C702D3C3"]
int oldminor;
@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *beacons;
@property (nonatomic, strong) NSArray *paintings;
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) CLBeaconRegion *beaconRegion;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_beacons = [[NSMutableArray alloc] init];
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID
identifier:@"lucainnoc.Ibeareader"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated
{
[_locationManager startRangingBeaconsInRegion:_beaconRegion];
}
- (void)viewDidDisappear:(BOOL)animated
{
[_locationManager stopRangingBeaconsInRegion:_beaconRegion];
}
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
{
if (beacons.count) {
CLBeacon *closestBeacon;
for (CLBeacon *beacon in beacons) {
NSLog([NSString stringWithFormat:@"%f", beacon.accuracy]);
}
}
}
@end
lunedì 26 maggio 2014
CC2540 vs CC2541
Il mio fornitore di beacon ha cambiato l'integrato passando da un CC2540 ad un CC2541 (entrambi Texas Instruments)
Ho fatto una breve prova per vedere se c'era una miglioramento sulla stabilita' del segnale
La prova (seppur con un numero modesto) e' stata fatta a geometria fissa evitando il piu' possibile di influenzare la misura
Ho fatto una breve prova per vedere se c'era una miglioramento sulla stabilita' del segnale
La prova (seppur con un numero modesto) e' stata fatta a geometria fissa evitando il piu' possibile di influenzare la misura
Alla fine e' emerso che il parametro Accuracy e' stato di
CC 2540 : 6.79+/-5.23
CC 2541 : 4.89+/-3.32
Con il 2540 la deviazione standard vale circa il 77% del valore medio mentre con il 2541 circa il 67%
Un miglioramento ma non certo sensibile
mercoledì 21 maggio 2014
IBeacon e direzione
Ho fatto qualche prova per vedere di poter replicare la navigazione con i radiofari (beacon) che veniva utilizzata in aeronautica prima dell'avvento delle nuove tecnologie
In pratica si puo' fare navigazione mettendo un trasmettitore con una antenna omnidirezionale (beacon) ed un ricevitore con una antenna direzionale. In questo modo l'aereo punta direttamente sul radiofaro massimizzando il segnale nella propria antenna direzionale
Si puo' fare qualcosa di simile con IBeacon ed i telefoni cellulari??
Per la prova ho preso un Motorola G ed un AprilBeacon ed ho scritto una piccola applicazione che legge i valori di RSSI di BT4
Dopo ogni serie di misure ho ruotato il telefono di 90° (mantenendolo alla stessa distanza) e ripreso le misure (l'angolo 0° coincide con il telefono puntato in direzione del beacon e 180° con il telefono orientato in direzione opposta al beacon
Serie 1
Come era lecito attendersi i valori di RSSI sono molto variabili e danno luogo a grandi valori della standard deviation. In ogni caso l'orientazione a 90° sembra sensibilmente quella con valori minori
In pratica si puo' fare navigazione mettendo un trasmettitore con una antenna omnidirezionale (beacon) ed un ricevitore con una antenna direzionale. In questo modo l'aereo punta direttamente sul radiofaro massimizzando il segnale nella propria antenna direzionale
Si puo' fare qualcosa di simile con IBeacon ed i telefoni cellulari??
Per la prova ho preso un Motorola G ed un AprilBeacon ed ho scritto una piccola applicazione che legge i valori di RSSI di BT4
Dopo ogni serie di misure ho ruotato il telefono di 90° (mantenendolo alla stessa distanza) e ripreso le misure (l'angolo 0° coincide con il telefono puntato in direzione del beacon e 180° con il telefono orientato in direzione opposta al beacon
Serie 1
Come era lecito attendersi i valori di RSSI sono molto variabili e danno luogo a grandi valori della standard deviation. In ogni caso l'orientazione a 90° sembra sensibilmente quella con valori minori
Serie 2
nella serie 2 i dati dell'angolo 0° sono decisamente anomali. In ogni caso si ha che ancora l'angolo 90° mostra i valori minori
In sostanza sembra che ci sia una certa direzionalita' nelle antenna BT dei telefoni cellulari ma i valori di RSSI sono cosi' poco affidabili da rendere sostanzialmente impossibile utilizzare nel mondo reale tale metodo
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...