Additional formatting

Michael Ingraham 2019-06-30 08:45:05 -04:00
parent 3bbbe30627
commit 2f6a1219dc
1 changed files with 13 additions and 14 deletions

@ -15,7 +15,7 @@ This wiki page is an attempt to document the Tasmota sensor API for sensor drive
* If your sensor has configuration options please make these available by using the `SensorXX` framework which is already incorporated in the base code - This may not stop you from using a web-based configuration interface but since web-based configuration takes up a lot of code space in flash it is very important to make this optional by means of a compiler directive or a #define in the configuration file and as such something you need to keep in mind during your development and debugging - The more progressively optional additional features are in your driver the smaller the basic codebase can be for minimalist implementations.
* Whilst developing drivers for devices that use the I<sup>2</sup>C bus always consider other devices already supported in the codebase which may use the same address range. This could mean you need to find a unique way of differentiating your device detection from other devices on the same address range (e.g. querying a model-specific register) and/or disabling by #undef existing devices if yours is selected with a #define statement and in such cases always provide a warning to the user during compile time using the #warning pragma such as including `#warning **** Turned off conflicting drivers SHT and VEML6070 ****` in your code.
* DO NOT ADD WEB INTERFACE FOR SENSOR CONFIGURATION if your sensor requires additional user configuration. The reason for this is the additional program memory required but most importantly the amount of RAM required to even create minimal user interfaces. Running out of RAM during runtime will lead to abnormal behaviour of your driver and/or other drivers or the entire firmware! See sensors such as the MCP23008/MCP23017 driver on more information on how to implement `SensorXX` commands instead!
* While developing you might want to enable additional debugging provided by file ``xdrv_95_debug.ino`` using define USE_DEBUG_DRIVER which provides some commands for managing configuration settings and CPU timing. In addition you can enable define PROFILE_XSNS_SENSOR_EVERY_SECOND to profile your drivers duration.
* While developing you might want to enable additional debugging provided by file ``xdrv_95_debug.ino`` using `#define USE_DEBUG_DRIVER` which provides some commands for managing configuration settings and CPU timing. In addition you can enable define `PROFILE_XSNS_SENSOR_EVERY_SECOND` to profile your drivers duration.
* Do not assume others will know immediately how to use your addition and know that you will need to write a Wiki for it in the end.
# Directory/file structure
@ -25,7 +25,7 @@ Using generic libraries from external sources for sensors should be avoided as f
# API structure
## Pre-processor directives
Conditional compiling of a sensor driver is achieved by adding a pre-processor directive of the scheme `USE_<driver_name>` in `user_config_override.h`. Accordingly the driver code has to be wrapped in `#ifdef USE_<driver_name> ... #endif // USE_<driver_name>`. Any Sensor driver must contain a pre-processor directive defining the driver ID by the scheme `#define XSNS_<driver_ID>`.
Conditional compiling of a sensor driver is achieved by adding a pre-processor directive of the scheme `USE_<driver_name>` in `my_user_config.h`. Accordingly the driver code has to be wrapped in `#ifdef USE_<driver_name> ... #endif // USE_<driver_name>`. Any Sensor driver must contain a pre-processor directive defining the driver ID by the scheme `#define XSNS_<driver_ID>`.
## Callback function
@ -99,7 +99,7 @@ This callback ID is called every second.
It can be useful for anything that you need to do on a per second basis and is commonly used as an entry point to detect a driver or initialize an externally driven device such as a sensor, relay board or other forms of input/output required by your driver.
You would normally want to make sure you've detected and initialised before it is used by JSON_APPEND etc so that its ready to serve data.
You would normally want to make sure you've detected and initialised before it is used by `JSON_APPEND`, etc. so that its ready to serve data.
The generally accepted way to use this would be to detect your sensor and once this is done set a sensor value accordingly so that the function does not use unnecessary resources during future calls, for example:
```c++
@ -124,7 +124,7 @@ Setting a flag that the driver was successful in detecting the attached chip/boa
When writing your function responsible for detecting an externally connected I<sup>2</sup>C device try to create a method by which you read or write to specific registers that would be applicable to that specific I<sup>2</sup>C device only as to confirm a positive detect for the device. If this is not done extensively it will lead to some drivers getting false detects for a different device type simply because it shares the same I<sup>2</sup>C address.
Unless your driver is specifically going to use the entire array of addresses provisioned by the manufacturer please consider using a #define USE_MYCHIPNAME_ADDR in the `user_config_override.h` so that the user may specify the address on which to expect the device. This is of course only applicable to drivers that are not enabled by default in any of the pre-built binaries.
Unless your driver is specifically going to use the entire array of addresses provisioned by the manufacturer please consider using a `#define USE_MYCHIPNAME_ADDR` in the `my_user_config.h` so that the user may specify the address on which to expect the device. This is of course only applicable to drivers that are not enabled by default in any of the pre-built binaries.
**I<sup>2</sup>C address auto-detection example**
```c++
@ -230,7 +230,7 @@ struct XDRVMAILBOX {
} XdrvMailbox;
```
If your driver needs to accept multiple parameters for `SensorXX` and/or DriverXX please consider using comma delimited formatting and use the already written subStr() function declared in support.ino to parse through the parameters you need.
If your driver needs to accept multiple parameters for `SensorXX` and/or `DriverXX` please consider using comma delimited formatting and use the already written `subStr()` function declared in `support.ino` to parse through the parameters you need.
An example of those could be
```c++
@ -255,7 +255,7 @@ ___
```c++
void MqttPublishPrefixTopic_P(uint8_t prefix, const char* subtopic, boolean retained)
```
This function publishes MQTT messages immediately, e.g.
This function publishes MQTT messages immediately, e.g.,
```c++
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"MPR121%c\":{\"Button%i\":%i}}"), pS->id[i], j, BITC(i,j));
MqttPublishPrefixTopic_P(RESULT_OR_STAT, mqtt_data);
@ -355,15 +355,14 @@ void I2cScan(char *devs, unsigned int devs_len)
This functions writes a list of I<sup>2</sup>C addresses in use into the string `*dev` with maximum length `devs_len`.
```c++
boolean I2cDevice(byte addr)
bool I2cDevice(byte addr)
```
This functions checks if the I<sup>2</sup>C address `addr` is in use.
## Useful pre-processor directives
```c++
PSTR("string")
```
`PSTR("string")`
This pre-processor directive saves RAM by storing strings in flash instead of RAM.
```c++
@ -375,7 +374,7 @@ You may then reference them directly (if the type matches the parameter required
# Keeping ESP8266 code compact
Below are various tips and tricks to keep ESP8266 code compact and save both Flash and Memory. Flash code is limited to 1024k but keep in mind that to allow OTA upgrade, you need Flash memory to contain two firmwares at the same time. To go beyond 512k, you typically use `sonoff-minimal` as an intermediate firmware. `sonoff-minimal` takes roughly 360k, so it's safe not to gouint32_t beyond 620k of Flash. Memory is even more limited: 80k. With Arduino Core and basic Tasmota, there are 25k-30k left of heap space. Heap memory is very precious, running out of memory will generally cause a crash.
Below are various tips and tricks to keep ESP8266 code compact and save both Flash and Memory. Flash code is limited to 1024k but keep in mind that to allow OTA upgrade, you need Flash memory to contain two firmwares at the same time. To go beyond 512k, you typically use `sonoff-minimal` as an intermediate firmware. `sonoff-minimal` takes roughly 360k, so it's safe not to go `uint32_t` beyond 620k of Flash. Memory is even more limited: 80k. With Arduino Core and basic Tasmota, there are 25k-30k left of heap space. Heap memory is very precious, running out of memory will generally cause a crash.
## About ESP8266
@ -427,14 +426,14 @@ _Z7Examplejj:
ret.n
```
Whenever gcc needs to convert from `uin32\_t` to `uint8_t`, it uses an extra instruction `extui <reg>, <reg>, 0, 8`.
Whenever gcc needs to convert from `uin32_t` to `uint8_t`, it uses an extra instruction `extui <reg>, <reg>, 0, 8`.
Whenever you allocate `uint8_t`as a local variable, it will anyways allocate 32 bits on the stack.
Whenever you allocate `uint8_t` as a local variable, it will anyways allocate 32 bits on the stack.
In conclusion you can easily use `uint32_t` in many places in the code. The main reason to force `uint8_t` are:
* in structures, to save memory. This is the only place where `uint8_t` will take 1 byte and the compiler will try to pack as much as 4 `uint8_t` in 32 bits
* when you want to ensure that the value can never exceed 255. Beware though that the compiler will just chunk the last 8 bits or a 32 bits value and will not report any overflow.
* when you want to ensure that the value can never exceed 255. Beware though that the compiler will just chunk the last 8 bits of a 32 bits value and will not report any overflow.
#### Loops