From wiki.ginstr.com
Jump to: navigation, search

Java class for direct interacting with ginstr IoT device through Bluetooth LE interface.

IoT class helps to create device object and provides the access to the device's hardware and software features using Bluetooth LE connection. The functionality of the described class is based on the “BLESSED for Android” library ([[1]]), licensed under MIT. This lib provides methods for BLE interaction.

Methods of IoT class could be applied without pairing with devices, which allows configuring/managing plenty of devices during one session.

Work with devices

After Bluetooth device was enabled, on the side of the ESP32 based IoT device the BLE server with GATT profile was created.


GATT structure

This server contains:

Name UUID Description
SERVICE
MAIN_SERVICE 6cca7d41-2342-4239-9e9b-adbece2094b0 The main device GATT service. By this service number it is possible to filter ginstr devices
CHARACTERISTICS
DIRECT_CONTROL_CHAR 53dae9e0-f30f-449f-be52-2e53df7c83b8

This characteristic is used for the main interacting workflow. Could be read / or written with a response. The device`s firmware uses “onwrite” callback for the direct processing of commands that were written in this characteristic.

DIRECT_READ_CHAR a95238b5-3c8d-493b-8ef7-5b3afa695cf6 This characteristic is used for response reading.

After sending some read commands into the DIRECT_CONTROL_CHAR, the result of the reading will be written to DIRECT_READ_CHAR. After reading the notification will be triggered and characteristic payload could be captured with help of the onCharacteristicUpdate callback method, provided by the BLEssed library. The filtering of incoming payloads is done by the command code containing.

STREAM_BUFFER_CHAR 53a60fb7-536d-412d-a86b-0145f1a30d01 This characteristic is used for transmission of big files, as long as GATT characteristic has a size limit of 20 bytes. During data transmission, the chunks of the message appear in this characteristic. After reading, the new one is written.
STREAM_FEATURES_CHAR 552c03a0-eb9c-4c1b-a811-09a135d6eb8d This characteristic is used for transmitting the additional features of transmitted data, such as crc32 hash and total chunks number.


Scanning

To get the list of available devices the scanForPeripherals() from the BLEssed library could be used. To get ONLY the list of ginst IoT devices, it is helpful to scan with filtering features with help of method scanForPeripheralsWithServices(UUID[] serviceUUIDs). As long as all ginstr devices would use the same MAIN_SERVICE uncial UUIDs, the scan result would always contain ginstr devices only.

After scanning the discovered periphery objects (IoT devices) would appear in the onDiscoveredPeripheral() callback from the BLEssed library.

To init the device, it is important to add the discovered device as a parameter into IoT class constructor, which could be done from the device discovered callback:

public List<IoT> discoveredDevicesList; 
....
public void onDiscoveredPeripheral( BluetoothPeripheral peripheral, ScanResult scanResult ) {
           Log.d("----NAME", scanResult.getScanRecord().getDeviceName());
           Log.d("----ADDRESS",scanResult.getDevice().getAddress());
           IoT dev = new IoT(peripheral);
           discoveredDevicesList.add(dev);
}


Discovered and created device objects could be stored in the global list object.

Before operations, the device should be connected with help of BLEssed library method from created central Bluetooth object:

central.connectPeripheral( discoveredDevicesList.get(0).peripheral, peripheralCallback );

Getting the device features

Device address the address can be obtained directly from the periphery features:

            IoT dev = new IoT(peripheral);
            String address = dev.getAddress()

Serial number: The serial number could be requested by calling the IoT class method getSerialNumber().

 IoT dev = new IoT(peripheral);
 boolean success = dev.getSerialNumber();


After request, the result would be captured by onCharacteristicUpdate callback and filtered by getting serial command content.

Work with config files

Uploading configuration XML file

The configuration file has an XML structure and can be loaded into device memory as a string to be parsed into configuration object on the firmware side further.

To load the config file as a string into the chosen device, there is IoT class method setConfigFile(String configFile) used. This method calculates CRC32 hash of the string, breaks it into chunks, and transmits it sequentially into the peripheral device.

Downloading configuration XML

To download configuration XML stored in the devices EEPROM memory, there is IoT class method getConfigFileDevice() used. This method makes a request, after which device starts transmitting the chunks of the file stored in the memory and used for configuration object generation.

After the file downloading request is firing up, the stream receiving mode appears activated by setting up the IoT class flag STREAM_DIRECTION to IN.

The incoming payload packets are capturing by onCharacteristicUpdate() callback method from BLEssed library and can be filtered by Characteristic UUID, as long as for data stream transmission the STREAM_BUFFER_CHAR is used. When the stream is started, there is another one characteristic appears updated: STREAM_FEATURES_CHAR. This characteristic holds the CRC32 hash of the string and total chunks number.

While new chunks are receiving, if the received chunk number is less than the size of the string in these chunks, the received chunk appends to the temporary buffer string object in the IoT class. If the last chunk received, the CRC32 hash from the buffered string is calculated. If the calculated CRC32 is equal to CRC32 from STREAM_FEATURES_CHAR, it is assumed that the string is valid and the receiving process was successful. After this, the IoT class flag streamStatus get the SUCCESS value and the compiled string could be yielded from IoT class String object LoadedFromStream.

Getting current config hash

To get the configuration hash stored in device, there is IoT class method getConfigHash() used.

The received payload could be captured in onCharacteristicUpdate() callback and filtered out by command ID.

Work with error log

The error log could be loaded in a way similar to downloading the configuration XML. After loading from the device's EEPROM memory, the table with error codes and timestamps appears converted into a delimiter separated string. The IoT class method getConfigUpdateErrorLogFromDevice() is used. After the request is done, the stream type is switched by setting up the IoT class flag streamType to ERRORS value When a loaded string appears been loaded in the IoT class string object LoadedFromStream, it can be converted to the HashMap<Long, Character> by calling IoT method getErrorsHashMap(String errorsString). The Long key from the HashMap would store timestamp value in UNIX format when character value would store error code

Operations with onboard periphery

The IoT class provides methods for accessing the onboard periphery devices directly.

Ginstr IoT device has a broad set of additional ports. Some of these ports are internally connected to the onboard devices, others can be configured for controlling the external devices, which is useful in case of work with a broad set of extension boards, expanding functionality and use cases.


Ports table

List of the physical ports which can be accessed directly provided in the table below.

* Multiplexed output could be configured as digital input multiplexer, but this is an experimental feature and would not be implemented yet. Also, these ports could be set up to achieve software PWM outputs (not implemented)

** Multiplexed port input could be used as interrupt inputs, but the setup of this feature have a sense with global configuration via XML file.

*** All physical pins accept interrupts digital interfaces and PWM (except pin 1, which is input only), but the setup of this feature have a sense with global configuration via XML file.

Port name Port group Descriptions Functions Port direction
GREEN_LED Onboard indication Port of green indication led Normal logic, the state could be setted or read Output only *
AMBER_LED Port of amber indication led
WHITE_LED Port of white indication led
BLUE_LED Port of blue indication led
D_BLUE Port of blue part of blue-red indication cell
D_RED Port of red part of blue-red indication cell
GSM Device power supply GSM modem power supply
LORA LoRa modem power supply Inverted logic, the state could be set or read
PERIPHERY_POWER Secondary periphery power management port
MUXOUT_1 Multiplexed port output Digital output port, could be used for turn on/off external devices Normal or inverted logic could be applied, port state could be setted or read
MUXOUT_2
MUXOUT_3
MUXOUT_4
MUXOUT_5
MUXIN_1 Multiplexed port input ** Anolog or digital read port 12 bit multiplexed Analog read, digital read Input only
MUXIN_2
MUXIN_3
MUXIN_4
MUXIN_5
MUXIN_6
MUXIN_7
MUXIN_8
PINPORT_1 Physical pin port *** ESP32 port 39 12 bit direct Analog read, digital read
PINPORT_2 ESP32 port 1 Digital read, digital write, PWM Input / Output
PINPORT_3 ESP32 port 3
PINPORT_4 ESP32 port 4
PINPORT_5 ESP32 port 5
PINPORT_6 ESP32 port 12
PINPORT_7 ESP32 port 32
PINPORT_8 ESP32 port 33


Inverted and non-inverted states

In the case of the discrete external devices connected (on/off option), there is 2 option of how do these devices can be switched off or on. To avoid misunderstandings and provide easy to follow logic, for port on/off the inversion enumeration (IoT.INVERTED.YES / NO) is provided.

Accordingly to electronics design, some devices could be activated by a LOW level (logic zero) on input. Ports with such devices should be used with an inversion flag. Other could be activated by HIGH level (logic 1). Writing and reading the periphery states

Direct write to port

The ports that have output port direction can be turned on / off, or PWM could be set up (for physical pins).

Discrete writing

For purpose of discrete writing, the IoT class method writePortDirect(PORT_REG port, POWER_STATE state, INVERSION is_inverted) is used. This method writes to the chosen device the command, which includes the port enumeration parameter, power state parameter (ON/OFF), and an inversion parameter (YES/NO). The method returns true if the writing was successful. So, in the case of calling IoT method

iot_device.writePortDirect(IoT.PORT_REG.GREEN_LED, IoT.POWER_STATE.ON, IoT.INVERSION.NO)

the green led will be turned on normally.

PWM writing (not implemented completely)

To interact with PwM possibilities of physical ports,the same IoT class method, but with different parameters writePortDirect(PORT_REG port, Integer frequency, Integer pulseWidth, INVERSION is_inverted) is used. This method writes to the chosen device the command, which includes the port enumeration parameter, base PWM frequency in Hertz, PWM width (0 -> 100 %), and an inversion parameter (YES/NO). The method returns true if the writing was successful. So, in the case of calling IoT method

iot_device.writePortDirect(IoT.PORT_REG.PINPORT_8, 10000, 40, IoT.INVERSION.NO)

the following pin would be configured as PWM output, and pulses on the PINPORT_8 would be produced.

Direct read from port

For the ports, that allow only output port direction, there is only the current set state reading feature available. In this case, the port state means not the physical value on the output (HIGH/LOW) but the written State. For the ports that allow input features, the current state could be red with help of IoT class method readPortDirect(PORT_REG port, PORT_READ_TYPE readType), where readType describes the data, which should be returned. If readType is DISCRETE, the returning value would be always binary, with this method it is possible to read digital levels from analog pins. If readType is RAW, returned from the device value would represent analog read value. If call this method for ports with PWM applied, the raw value will represent actual PWM width.

The returned value will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by command sign.

Operations with data storage registers

The registers are the key-value storage units that could be used to store the custom values, which could be used in the internal logic.

Table of pre-defined registers

This table describes read-only registers, from which the onboard periphery and sensors telemetry information could be read.

Register name Descriptions Data type
THERMO_NOW_REG Data from temperature sensor in Celsius degrees Float
THERMO_DAYMAX_REG Maximal temperature detected during the day Float
THERMO_DAYMIN_REG Minimal temperature detected during the day Float
CURRENT_NOW_REG Data from power current sensor, uA Float
CURRENT_DAYMAX_REG Maximal current consumption during the day, uA Float
CURRENT_DAYMIN_REG Minimal current consumption during the day, uA Float
CURRENT_SUMM_REG Summary current consumption during the day, mA Float
VOLTAGE_NOW_REG Data from power source voltage sensor, VDC Float
VOLTAGE_DAYMAX_REG Maximal power voltage detected during the day, VDC Float
VOLTAGE_DAYMIN_REG Minimal power voltage detected during the day, VDC Float
GSTATS_DAYMEAN_REG Daily mean data from g-sensor Float
GSTATS_DAYMAX_REG Maximal value from g-sensor detected during the day Float
GSTATS_DAYMIN_REG Minimal valuable value from g-sensor detected during the day Float
RTC_NOW_REG Current device time in millis Long
POWERON_REG Seconds after last boot Long


Registers reading

For the values of the registers reading, the IoT class method readRegisterDirect(String key) should be used, where key is the value should be red.

The returned value will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by a command sign.

Registers writing

To set the custom register value, the IoT class method writeRegisterDirect(String key, int value | String value | float value, boolean value) is used. This method writes the value of the provided type into the storage with the provided key.

To write the threshold value of some temperature parameter, for example, the method should be used as bellow:

iot_device.writeRegisterDirect("temp1", 23.4);

Helper methods

Device identification

To identify a device among others by visual blinking, the IoT class method identifyDevice() is used. After calling

iot_device.identifyDevice();

The attached device should blink with all leads.

Device state summary hashes

To get the periphery state summary, it is IoT class method getStatusDevice() is used. After calling

iot_device.getStatusDevice();

The returned data will be captured by onCharacteristicUpdate callback from the BLEssed library and filtered by a command sign. The datatype of the payload is byte[]. This byte array could be decrypted into actual statuses with IoT class method HashMap<PORT_REG, LOGIC_STATE> decryptStatuses(byte[] hash)

byte[] statuses = statusHash.getBytes();
HashMap<IoT.PORT_REG, IoT.LOGIC_STATE> decrypted = iot.decryptStatuses(statuses);

where IoT.PORT_REG corresponds the port register from port registers enumeration, and IoT.LOGIC_STATE corresponds logic states enumeration, and could get value of either HIGH or LOW


Device blocking

API summary

Enumerations

Methods