当前位置:网站首页>Internet of things development practice 18 scenario linkage: how does an intelligent light perceive light? (I) (learning notes)

Internet of things development practice 18 scenario linkage: how does an intelligent light perceive light? (I) (learning notes)

2022-06-11 21:53:00 Xiaohui_ Super

Learn only as yourself 《 The development of the Internet of things 》 Learning notes of , Link to the original course : Geek time 《 The development of the Internet of things 》—— Guo Chaobin

First step : Communications technology

Mr. Guo suggested choosing BLE Low power Bluetooth technology as a means of communication for light sensor devices . Because the deployment position of sensors is flexible , So you can't use the power cord directly , But need to use wireless communication technology , Again because BLE Power consumption ratio Wi-Fi low , So we choose BLE Communications technology .

BLE The device can be in 4 Working in two modes :

  1. Broadcast mode (Boradcaster), Simple broadcast mode . In this mode, the device cannot be connected , Data can only be broadcast at certain intervals , Use of other equipment , For example, mobile phone scanning processing .
  2. Slave mode (Peripheral), In this mode, the device can still broadcast data , It can also be connected . Once the connection is established , Both parties can communicate in two directions .
  3. Host mode (Central), In this mode, the device cannot broadcast , But you can scan the surrounding Bluetooth broadcast packets , Discover other devices , Then initiate the connection to these devices .
  4. Observer mode (Observer), In this mode, the device is like the host mode , And no broadcast , Instead, scan the surrounding Bluetooth broadcast packets , But the difference is , It will not establish a connection with the slave . Generally, the gateway that collects the broadcast packets of Bluetooth devices works in this mode .

In this lecture , The light sensor only needs to provide light intensity data , So we can make it work in broadcast mode .

The second step : Choose development board

The development board is still NodeMCU, You need to use a method based on ESP32 Chip NodeMCU Development board , It also supports Wi-Fi And low power Bluetooth communication technology , There are still a lot of it ADC Interface .

The third step : Get ready MicroPython Environmental Science

Environment construction can refer to 《 The development of the Internet of things 》16 Actual combat preparation : How to build a hardware development environment ?( Learning notes )

Step four : Build the hardware circuit of the light sensor

The following is Mr. Guo's wiring diagram :

 Insert picture description here

Mr. Guo chose to be based on PT550 Environmental protection photodiode light sensor components , It is more sensitive , The measurement range is 0Lux~6000Lux.

This component outputs analog quantity through signal pin , We read NodeMCU ESP32 Of ADC Value of analog-to-digital converter (ADC7,GPIO35), You can get the intensity of the light . The larger the number , It means that the greater the light intensity .

ADC The maximum accuracy supported is 12 bit, The corresponding decimal system is 0~4095, We need to compare the voltage value with ADC Value to do a linear transformation , You can refer to the following code ( From the original )

from machine import ADC
from machine import Pin

class LightSensor():
	def __init__(self, pin):
		self.light = ADC(Pin(pin))
	
	def value(self):
		value = self.light.read()
		print("Light ADC value:", value)
		return int(value/4096*6000)

Step five : Programming Bluetooth

NodeMCU ESP32 The firmware of has been integrated BLE function , But we also need to define a certain format for broadcast packet data , So that other devices can successfully parse and use the scanned data .

How to define the format of Bluetooth broadcast packets ? Mr. Guo recommended Xiaomi's customized MiBeacon Bluetooth protocol .

In order to make it convenient for users to use Mi Jia APP And Bluetooth gateway , Can quickly find and communicate with BLE The device is connected , millet IoT Platform in BLE In the broadcast of the equipment ( be based on BLE agreement 4.0), Added Xiaomi service data (ServiceData UUID 0xFE95, namely Mibeacon), send BLE The device can identify its own identity and type when broadcasting data , It can be recognized and connected by users or Bluetooth gateway in time ; Besides , In order to better improve BLE The ability of intelligent equipment ,BLE MiBeacon The protocol also supports developers to meet their actual needs , Select Add Object Field , Through the gateway to Xiaomi IoT The platform reports BLE Event information and status information of equipment ( attribute ), Realize the functions of remote reporting and intelligent linkage of equipment status .

https://iot.mi.com/

MiBeacon The broadcast packet format of Bluetooth protocol is based on BLE Of GAP(Generic Access Profile) To formulate the .GAP Control the broadcast and connection of Bluetooth , Which controls how devices are discovered , And how to interact .

say concretely ,GAP Two ways are defined to let the device broadcast data :
One is broadcast data (Advertising Data payload), This is a must , Data length is 31 Bytes ;
The other is to scan the reply data (Scan Response payload), It is based on Bluetooth host devices ( Like mobile phone. ) Scan request sent (Scan Request) To respond to some additional information . The data length is the same as broadcast data .
( Be careful , bluetooth 5.0 There is extended broadcast data in , Data length and other characteristics are different , But it doesn't involve , So I won't introduce .)

therefore , As long as the broadcast message contains the following specified information , It can be considered as conforming to MiBeacon Bluetooth protocol .

1 . Advertising Data in Service Data(0x16) contain Mi Service UUID The radio bag ,UUID yes 0xFE95.
2 . Scan Response in Manufacturer Specific Data(0xFF) Broadcast package containing Xiaomi company identification code , Identification code ID yes 0x038F.

among , Whether in the Advertising Data in , still Scan Response in , Are defined in a unified format . According to the broadcast message format definition of the figure , Please refer to the table below .

—— original text

name length (byte) Whether must describe
Frame Control2 must Control bits
Product ID2 must product ID, Need to be in Xiaomi IoT Development platform application
Frame Counter1 must Serial number , Used to remove heavy
MAC Address6 be based on Frame Control equipment Mac Address
Capability1 be based on Frame Control Equipment capacity
I/O capability2 be based on CapacityI/O Ability , At present, there is only high security level BLE This field is only used for access
Objectn( According to the actual demand ) be based on Frame Control Trigger event or broadcast attribute
Random Number3 be based on Frame Control Required if encrypted , And Frame Counter Merge into 4 byte Counter, Used to prevent replay
Message Integrity Check4 be based on Frame Control Required if encrypted ,MIC Four bytes

Because we need to increase the ability of the light sensor to broadcast light intensity data , So we need to focus on Object The definition of .

 Insert picture description here

according to MiBeacon The definition of , Light sensor Object ID yes 0x1007, Data length 3 Bytes , The range of values is 0~120000.

The following is the reference code provided by Mr. Guo 【 Slightly modified , Otherwise I can't run on my board 】:

#file: ble_lightsensor.py
import bluetooth
import struct
import time
from ble_advertising import advertising_payload

from micropython import const

_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_INDICATE_DONE = const(20)

_FLAG_READ = const(0x0002)
_FLAG_NOTIFY = const(0x0010)

_ADV_SERVICE_DATA_UUID = 0xFE95
_SERVICE_UUID_ENV_SENSE = 0x181A
_CHAR_UUID_AMBIENT_LIGHT = 'FEC66B35-937E-4938-9F8D-6E44BBD533EE'

# Service environmental sensing
_ENV_SENSE_UUID = bluetooth.UUID(_SERVICE_UUID_ENV_SENSE)
# Characteristic ambient light density
_AMBIENT_LIGHT_CHAR = (
    bluetooth.UUID(_CHAR_UUID_AMBIENT_LIGHT),
    _FLAG_READ | _FLAG_NOTIFY ,
)
_ENV_SENSE_SERVICE = (
    _ENV_SENSE_UUID,
    (_AMBIENT_LIGHT_CHAR,),
)

# https://specificationrefs.bluetooth.com/assigned-values/Appearance%20Values.pdf
_ADV_APPEARANCE_GENERIC_AMBIENT_LIGHT = const(1344)

class BLELightSensor:
    def __init__(self, ble, name='Nodemcu'):
        self._ble = ble
        self._ble.active(True)
        self._ble.irq(self._irq)
        ((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
        self._connections = set()
        time.sleep_ms(500)
        self._payload = advertising_payload(
            name=name, services=[_ENV_SENSE_UUID], appearance=_ADV_APPEARANCE_GENERIC_AMBIENT_LIGHT
        )
        self._sd_adv = None
        self._advertise()

    def _irq(self, event, data):
        # Track connections so we can send notifications.
        if event == _IRQ_CENTRAL_CONNECT:
            conn_handle, _, _ = data
            self._connections.add(conn_handle)
        elif event == _IRQ_CENTRAL_DISCONNECT:
            conn_handle, _, _ = data
            self._connections.remove(conn_handle)
            # Start advertising again to allow a new connection.
            self._advertise()
        elif event == _IRQ_GATTS_INDICATE_DONE:
            conn_handle, value_handle, status = data

    def set_light(self, light_den, notify=False):
        self._ble.gatts_write(self._handle, struct.pack("!h", int(light_den)))
        self._sd_adv = self.build_mi_sdadv(light_den)
        self._advertise()
        if notify:
            for conn_handle in self._connections:
                if notify:
                    # Notify connected centrals.
                    self._ble.gatts_notify(conn_handle, self._handle)

    def build_mi_sdadv(self, density):
        
        uuid = 0xFE95
        fc = 0x0010
        pid = 0x0002
        fcnt = 0x01
        mac = self._ble.config('mac')
        objid = 0x1007
        objlen = 0x03
        objval = density

        service_data = struct.pack("<3HB",uuid,fc,pid,fcnt)+mac[1]+struct.pack("<H2BH",objid,objlen,0,objval)

        print("Service Data:",service_data)
        
        return advertising_payload(service_data=service_data)
        
    def _advertise(self, interval_us=500000):
        self._ble.gap_advertise(interval_us, adv_data=self._payload)
        time.sleep_ms(100)

        print("sd_adv",self._sd_adv)
        if self._sd_adv is not None:
            print("sdddd_adv",self._sd_adv)
            self._ble.gap_advertise(interval_us, adv_data=self._sd_adv)
# File: main.py
from ble_lightsensor import BLELightSensor
from lightsensor import LightSensor
import time
import bluetooth

def main():
    ble = bluetooth.BLE()
    ble.active(True)
    ble_light = BLELightSensor(ble)

    light = LightSensor(35)
    light_density = light.value()
    i = 0

    while True:
        # Write every second, notify every 10 seconds.
        i = (i + 1) % 10
        ble_light.set_light(light_density, notify=i == 0)
        print("Light Lux:", light_density)

        light_density = light.value()
        time.sleep_ms(1000)

if __name__ == "__main__":
    main()

In addition to the above 3 individual Python Script , I need one more ble_advertising.py, You can go to MicroPython Official Bluetooth Get... From the example , Address :https://github.com/micropython/micropython/tree/master/examples/bluetooth

radio broadcast service data I have adjusted this function for a long time without success , Finally found ....:
 Insert picture description here

Here is my use of ble_advertising.py Script files :

# Helpers for generating BLE advertising payloads.

from micropython import const
import struct
import bluetooth

# Advertising payloads are repeated packets of the following form:
# 1 byte data length (N + 1)
# 1 byte type (see constants below)
# N bytes type-specific data

_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)
_ADV_TYPE_SERVICE_DATA = const(0x16)


# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0, service_data = None):
    payload = bytearray()

    def _append(adv_type, value):
        nonlocal payload
        payload += struct.pack("BB", len(value) + 1, adv_type) + value

    _append(
        _ADV_TYPE_FLAGS,
        struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
    )

    if name:
        _append(_ADV_TYPE_NAME, name)

    if services:
        for uuid in services:
            b = bytes(uuid)
            if len(b) == 2:
                _append(_ADV_TYPE_UUID16_COMPLETE, b)
            elif len(b) == 4:
                _append(_ADV_TYPE_UUID32_COMPLETE, b)
            elif len(b) == 16:
                _append(_ADV_TYPE_UUID128_COMPLETE, b)

    # See org.bluetooth.characteristic.gap.appearance.xml
    if appearance:
        _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))

    if service_data:
        _append(_ADV_TYPE_SERVICE_DATA, service_data)

    return payload


def decode_field(payload, adv_type):
    i = 0
    result = []
    while i + 1 < len(payload):
        if payload[i + 1] == adv_type:
            result.append(payload[i + 2 : i + payload[i] + 1])
        i += 1 + payload[i]
    return result


def decode_name(payload):
    n = decode_field(payload, _ADV_TYPE_NAME)
    return str(n[0], "utf-8") if n else ""


def decode_services(payload):
    services = []
    for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
        services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
    for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
        services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
    for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
        services.append(bluetooth.UUID(u))
    return services


def demo():
    payload = advertising_payload(
        name="micropython",
        services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
    )
    print(payload)
    print(decode_name(payload))
    print(decode_services(payload))


if __name__ == "__main__":
    demo()

Step six : Verify the light sensor

Next, we need to verify whether the equipment is working properly , First, use the serial port terminal to check the program operation , The terminal prints the message sent by the device Service Data, And light intensity and light sensor ADC value :

 Insert picture description here
Next, download a Bluetooth debugging with your mobile phone APP, The original text recommends 3 paragraph (LightBlue、nRFConnect、BLEScanner), You can also use any other similar software .

The Bluetooth name of the device is “Nodemcu”, This is BLELightSensor Class __init__() Function ,

 Insert picture description here

Check the Bluetooth broadcast package , There's something wrong with it ...( Is it the debugging assistant ?)

 Insert picture description here

原网站

版权声明
本文为[Xiaohui_ Super]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206112137062067.html