{"id":135814,"date":"2018-11-08T16:05:00","date_gmt":"2018-11-08T14:05:00","guid":{"rendered":"https:\/\/ruuvi.com\/eigenes-ruuvi-datenformat-an-einem-tag\/"},"modified":"2026-06-11T08:48:56","modified_gmt":"2026-06-11T05:48:56","slug":"eigenes-ruuvi-datenformat-an-einem-tag","status":"publish","type":"post","link":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/","title":{"rendered":"Eigenes Ruuvi-Datenformat an einem Tag"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"506\" src=\"https:\/\/ruuvi.com\/i\/u\/graph-overview-1024x506.png\" alt=\"Graph mit Spannungs&#xFC;bersicht\" class=\"wp-image-2957\" srcset=\"https:\/\/ruuvi.com\/i\/u\/graph-overview-1024x506.png 1024w, https:\/\/ruuvi.com\/i\/u\/graph-overview-450x222.png 450w, https:\/\/ruuvi.com\/i\/u\/graph-overview-768x379.png 768w, https:\/\/ruuvi.com\/i\/u\/graph-overview-1536x758.png 1536w, https:\/\/ruuvi.com\/i\/u\/graph-overview-2048x1011.png 2048w, https:\/\/ruuvi.com\/i\/u\/graph-overview-600x296.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">K\u00fcrzlich haben wir bei der <a href=\"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/\" target=\"_blank\" rel=\"noreferrer noopener\">Entwicklung der offiziellen Ruuvi-Firmware<\/a> etwas Interessantes bemerkt: Die Batteriespannung zeigt einen erheblichen Spannungseinbruch bei der Funk\u00fcbertragung.<\/p>\n\n<p class=\"wp-block-paragraph\">Diese Entdeckung rechtfertigt weitere Untersuchungen zur Messung des Batteriestands. Hier stellen wir den allgemeinen Arbeitsablauf vor. Bitte beachte, dass wir unsere Arbeit auf der Firmware-Version <em>3.140-alpha<\/em> basieren \u2013 die hier gegebenen Codebeispiele funktionieren m\u00f6glicherweise nicht mit sp\u00e4teren Branches.  <\/p>\n\n<h2 class=\"wp-block-heading\">Gute Planung ist der halbe Erfolg.<\/h2>\n\n<p class=\"wp-block-paragraph\">Bevor wir uns ans Programmieren machen, sollten wir festlegen, was wir eigentlich erreichen wollen. Unser Ziel ist es, drei verschiedene Spannungsmessmethoden hinsichtlich ihrer Vorhersagekraft f\u00fcr die verbleibende Batterielebensdauer zu vergleichen: <\/p>\n\n<ul class=\"wp-block-list\"><li>Wir m\u00fcssen jede dieser Messungen in unserer Firmware implementieren<\/li><li>Die Daten m\u00fcssen Luftfeuchtigkeit und Temperatur enthalten<\/li><li>Die Daten m\u00fcssen einen laufenden Z\u00e4hler enthalten, um spontane Neustarts zu erkennen<\/li><li>Der Stromverbrauch sollte ausreichen, um die Batterie innerhalb eines angemessenen Zeitrahmens zu entleeren<\/li><li>Die Daten m\u00fcssen per Bluetooth an ein Gateway gesendet werden, das die Daten an einen externen Server weiterleitet.<\/li><li>Der externe Server muss \u00fcber eine benutzerfreundliche Oberfl\u00e4che zur Anzeige der Daten verf\u00fcgen.<\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">Ohne weitere Umschweife, legen wir los.<\/p>\n\n<h2 class=\"wp-block-heading\">Implementierung jeder dieser Messungen<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir schauen uns 3 verschiedene Methoden zur Spannungsabtastung an. Die erste ist der \u201enaive\u201c Ansatz, die Spannung ab und zu zu messen. Die zweite ist eine ausgefeiltere Methode, bei der direkt nach Funkaktivit\u00e4t gemessen wird. Die dritte besteht darin, nach der Funkaktivit\u00e4t zu messen und einige Millisekunden sp\u00e4ter erneut, um zu sehen, wie stark die Spannung unter Last einbricht.   <\/p>\n\n<h3 class=\"wp-block-heading\">Einrichten des Projekts<\/h3>\n\n<p class=\"wp-block-paragraph\">Zuerst wollen wir dieses Projekt vom Haupt-Branch abspalten. Erstellen wir ein leeres Repository <a href=\"https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c\" target=\"_blank\" rel=\"noreferrer noopener\"><em>ojousima.nrf52_batterytest.c<\/em><\/a> auf Github und spiegeln das <a href=\"https:\/\/github.com\/ruuvi\/ruuvi.firmware.c\" target=\"_blank\" rel=\"noreferrer noopener\"><em>ruuvi.firmware.c<\/em><\/a> dorthin. Das Github-Repository wird \u00fcber die <a href=\"https:\/\/help.github.com\/articles\/create-a-repo\/\" target=\"_blank\" rel=\"noreferrer noopener\">Github-Benutzeroberfl\u00e4che<\/a> erstellt.  <\/p>\n\n<p class=\"wp-block-paragraph\">Das vorhandene Repository wird geklont und der neue Master mit diesen Konsolenbefehlen eingerichtet:<\/p>\n\n<pre class=\"wp-block-preformatted\">$ git clone --bare <a href=\"https:\/\/github.com\/ojousima\/ruuvi.firmware.c.git\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/ruuvi\/ruuvi.firmware.c.git<\/a><br\/>$ cd ruuvi.firmware.c.git\/<br\/>$ git push --mirror <a href=\"https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c.git\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c.git<\/a><br\/>$ cd ..<br\/>$ rm -rf ruuvi.firmware.c.git\/<br\/>$ git clone <a href=\"https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c<\/a><br\/>$ cd <a href=\"https:\/\/github.com\/ojousima\/ojousima.nrf52_batterytest.c\" target=\"_blank\" rel=\"noreferrer noopener\">ojousima.nrf52_batterytest.c<\/a><br\/>$ git checkout 3.14.0-alpha<br\/>$ git branch -D master<br\/>$ git checkout -b master<br\/>$ git push -f origin master<br\/>$ git submodule update --init --recursive<\/pre>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes benennen wir die Projektdateien um:<\/p>\n\n<pre class=\"wp-block-preformatted\">$ find . -name \"ruuvi.firmware.c*\" -exec sh -c 'mv \"$1\" \"${1\/ruuvi.firmware.c\/ojousima.nrf52_batterytest.c}\"' _ {} \\; <\/pre>\n\n<p class=\"wp-block-paragraph\">Und dann ersetzen wir alle Vorkommen von <em>ruuvi.firmware.c<\/em> durch <em>ojousima.nrf52_batterytest.c<\/em>. Achte darauf, das Ersetzen nicht im gesamten Projekt auszuf\u00fchren, da es bei Ausf\u00fchrung im Ordner <em>.git<\/em> deinen Git-Index besch\u00e4digen k\u00f6nnte. <\/p>\n\n<pre class=\"wp-block-preformatted\">$ grep -rl \"ruuvi.firmware.c\" .\/application_config\/* | xargs sed -i -e 's\/ruuvi.firmware.c\/ojousima.nrf52_batterytest.c\/g'<br\/>$ grep -rl \"ruuvi.firmware.c\" .\/targets\/* | xargs sed -i -e 's\/ruuvi.firmware.c\/ojousima.nrf52_batterytest.c\/g'<\/pre>\n\n<p class=\"wp-block-paragraph\">Committen wir unsere Arbeit und pr\u00fcfen, ob sie sich mit <a href=\"https:\/\/www.segger.com\/products\/development-tools\/embedded-studio\/\" target=\"_blank\" rel=\"noreferrer noopener\">Segger Embedded Studio<\/a> sauber kompilieren l\u00e4sst.<\/p>\n\n<pre class=\"wp-block-preformatted\">$ git add .<br\/>$ git commit -m \"Rename project\"<\/pre>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"216\" src=\"https:\/\/ruuvi.com\/i\/u\/output-transcript-1024x216.png\" alt=\"Ausgabe zeigt, dass bisher alles gut l&#xE4;uft\" class=\"wp-image-2959\" srcset=\"https:\/\/ruuvi.com\/i\/u\/output-transcript-1024x216.png 1024w, https:\/\/ruuvi.com\/i\/u\/output-transcript-450x95.png 450w, https:\/\/ruuvi.com\/i\/u\/output-transcript-768x162.png 768w, https:\/\/ruuvi.com\/i\/u\/output-transcript-1536x324.png 1536w, https:\/\/ruuvi.com\/i\/u\/output-transcript-600x127.png 600w, https:\/\/ruuvi.com\/i\/u\/output-transcript.png 1998w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Bisher l\u00e4uft alles gut<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Konfigurieren des Projekts<\/h2>\n\n<p class=\"wp-block-paragraph\"><em>Als N\u00e4chstes passen wir die application_config\/application_config.h an<\/em>. Der Beschleunigungssensor wird deaktiviert und wir entfernen die Spannungsmodusauswahl von <em>ruuvi.firmware.c<\/em>. Die <strong>ADC<\/strong>-Aufl\u00f6sung wird in Zeile <strong>77<\/strong> auf <strong>12<\/strong> Bit gesetzt. <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Application configuration constants\n *\n * License: BSD-3\n * Author: Otso Jousimaa &lt;otso@ojousima.net&gt;\n *\/\n\n#ifndef APPLICATION_CONFIG_H\n#define APPLICATION_CONFIG_H\n\n#define APPLICATION_FW_VERSION \"Batterytest 1.0.0\"\n\n\/\/ Pick a power of 2 for nRF5 backend. 128 is recommended minimum\n#define APPLICATION_LOG_BUFFER_SIZE              256\n\n\/\/ Use nRF5 SDK15\n#define NRF5_SDK15_PLATFORM_ENABLED              1\n\n\/**\n * Environmental sensor configuration\n **\/\n\/\/ Sample rate is in Hz. This configures only the sensor,\n\/\/ not transmission rate of data.\n#define APPLICATION_ENVIRONMENTAL_SAMPLERATE RUUVI_DRIVER_SENSOR_CFG_MIN\n\n\/\/ Resolution and scale cannot be adjusted on BME280\n#define APPLICATION_ENVIRONMENTAL_RESOLUTION RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n#define APPLICATION_ENVIRONMENTAL_SCALE      RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n\n\/\/ Valid values for BME280 are: (RUUVI_DRIVER_SENSOR_DSP_)LAST, IIR, OS\n\/\/ IIR slows step response but lowers noise\n\/\/ OS increases power consumption but lowers noise.\n\/\/ See https:\/\/blog.ruuvi.com\/humidity-sensor-673c5b7636fc\n\/\/ and https:\/\/blog.ruuvi.com\/dsp-compromises-3f264a6b6344\n#define APPLICATION_ENVIRONMENTAL_DSPFUNC    RUUVI_DRIVER_SENSOR_DSP_IIR\n\n\/\/ No effect on _LAST, use 1. On _OS and _IIR valid values are 2, 4, 8 and 16.\n#define APPLICATION_ENVIRONMENTAL_DSPPARAM   RUUVI_DRIVER_SENSOR_CFG_MAX\n\n\/\/ (RUUVI_DRIVER_SENSOR_CFG_)SLEEP, SINGLE or CONTINUOUS\n#define APPLICATION_ENVIRONMENTAL_MODE       RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS\n\n\/\/ Allow BME280 support compilation\n#define RUUVI_INTERFACE_ENVIRONMENTAL_BME280_ENABLED 1\n\n\/**\n * Accelerometer configuration\n **\/\n\/\/ 1, 10, 25, 50, 100, 200 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_SAMPLERATE 10\n\n\/\/ 8, 10, 12 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_RESOLUTION 10\n\n\/\/ 2, 4, 8, 16 for LIS2DH12\n#define APPLICATION_ACCELEROMETER_SCALE   RUUVI_DRIVER_SENSOR_CFG_MIN\n\n\/\/ LAST or HIGH_PASS\n#define APPLICATION_ACCELEROMETER_DSPFUNC RUUVI_DRIVER_SENSOR_DSP_LAST\n#define APPLICATION_ACCELEROMETER_DSPPARAM 1\n\n\/\/ SLEEP or CONTINUOUS\n#define APPLICATION_ACCELEROMETER_MODE RUUVI_DRIVER_SENSOR_CFG_SLEEP\n\n\/\/ Up to scale of sensor, interpreted as \"at least\"\n#define APPLICATION_ACCELEROMETER_ACTIVITY_THRESHOLD 0.100f\n\n\n\/\/ Allow LIS2DH12 support compilation\n#define RUUVI_INTERFACE_ACCELERATION_LIS2DH12_ENABLED 0\n\n\/**\n *  ADC configuration\n *\/\n \/\/ Valid for continuous mode\n#define APPLICATION_ADC_SAMPLERATE         RUUVI_DRIVER_SENSOR_CFG_MIN\n#define APPLICATION_ADC_RESOLUTION         12\n#define APPLICATION_ADC_SCALE              RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n#define APPLICATION_ADC_DSPFUNC            RUUVI_DRIVER_SENSOR_DSP_LAST\n#define APPLICATION_ADC_DSPPARAM           1\n\/\/ Note: call to task_adc_sample will leave the ADC in single-shot mode.\n#define APPLICATION_ADC_MODE               RUUVI_DRIVER_SENSOR_CFG_SINGLE\n\/\/ Milliseconds between active and recovered tx\n#define APPLICATION_BATTERY_DROOP_DELAY_MS 10\n\n\/**\n * Bluetooth configuration\n *\n *\/\n\/\/ Avoid \"even\" values such as 100 or 1000 to eventually drift apart\n\/\/ from the devices transmitting at same interval\n#define APPLICATION_ADVERTISING_INTERVAL 1010\n#define APPLICATION_ADVERTISING_POWER    RUUVI_BOARD_TX_POWER_MAX\n#define APPLICATION_DATA_FORMAT 0xBA\n\n\/**\n * NFC configuration\n *\/\n\/\/ Longest text in a text field, i.e. \"FW: ojousima.nrf52_batterytest.c 3.10.0\n#define APPLICATION_COMMUNICATION_NFC_TEXT_BUFFER_SIZE (32)\n\/\/ Longest binary message\n#define APPLICATION_COMMUNICATION_NFC_DATA_BUFFER_SIZE \\\n        APPLICATION_COMMUNICATION_NFC_TEXT_BUFFER_SIZE\n\/\/ 3 text records (version, address, id) and a data record\n#define APPLICATION_COMMUNICATION_NFC_MAX_RECORDS      (4)\n\/\/ 2 length bytes + 3 * text record + 1 * data record + 4 * 9 bytes for record header\n\/\/ Conservers RAM for 3 * text buffer size + 1 * data buffer size + NDEF_FILE_SIZE\n#define APPLICATION_COMMUNICATION_NFC_NDEF_FILE_SIZE   (166)\n\n\/**\n * Task scheduler configuration\n *\/\n#define APPLICATION_TASK_DATA_MAX_SIZE 0\n#define APPLICATION_TASK_QUEUE_MAX_LENGTH 10\n\n\/**\n * Flags which determine which c-modules are compiled in.\n * These modules may reserve some RAM and FLASH, so if you\n * do not need module you can disable it. The modules might also\n * have some dependencies between themselves.\n *\/\n#define APPLICATION_ADC_ENABLED                     1\n#define APPLICATION_COMMUNICATION_ENABLED           1\n#define APPLICATION_COMMUNICATION_BLUETOOTH_ENABLED 1\n#define APPLICATION_COMMUNICATION_NFC_ENABLED       1\n#define APPLICATION_GPIO_ENABLED                    1\n#define APPLICATION_GPIO_INTERRUPT_ENABLED          1\n#define APPLICATION_ENVIRONMENTAL_MCU_ENABLED       1\n#define APPLICATION_ENVIRONMENTAL_BME280_ENABLED    1\n#define APPLICATION_POWER_ENABLED                   1\n#define APPLICATION_RTC_MCU_ENABLED                 1\n#define APPLICATION_SCHEDULER_ENABLED               1\n#define APPLICATION_SPI_ENABLED                     1\n#define APPLICATION_TIMER_ENABLED                   1\n#define APPLICATION_YIELD_ENABLED                   1\n#define APPLICATION_LOG_ENABLED                     1\n\/\/ (RUUVI_INTERFACE_LOG)_ERROR, _WARNING, _INFO, _DEBUG\n#define APPLICATION_LOG_LEVEL                       RUUVI_INTERFACE_LOG_INFO\n\n\/\/ Choose one. RTT is recommended, but does not work on devices\n\/\/ with readback protection enabled\n#define APPLICATION_LOG_BACKEND_RTT_ENABLED         1\n\/\/#define APPLICATION_LOG_BACKEND_UART_ENABLED      0 \/\/ UART not implemented\n\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/630d314eb3ffb2f880888ffdf592d800\/raw\/df067e229efd3e11f531cf54b56289cf469216a6\/ojousima.nrf52_batterytest.c_application_config.h\">Rohdaten anzeigen<\/a><\/p>\n\n<h3 class=\"wp-block-heading\">Implementierung der Tasks<\/h3>\n\n<p class=\"wp-block-paragraph\">Wir m\u00fcssen 2 Tasks in unserer Anwendung anpassen: <a href=\"https:\/\/ruuvi.com\/de\/ruuvi-firmware-teil-13-batteriemessung-mit-funk-synchronisiert\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>task_adc<\/em><\/a> und <a href=\"https:\/\/ruuvi.com\/ruuvi-firmware-part-9-bluetooth-broadcasting\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>task_advertising<\/em><\/a><em>. <\/em>Unser <em>task_adc<\/em> wird tats\u00e4chlich etwas einfacher, da wir den Modus des <strong>ADC<\/strong> nicht nach dem ausgew\u00e4hlten Modus konfigurieren m\u00fcssen, sondern alle Messungen durchf\u00fchren.<\/p>\n\n<pre class=\"wp-block-code\"><code>#include \"application_config.h\"\n#include \"ruuvi_boards.h\"\n#include \"ruuvi_driver_error.h\"\n#include \"ruuvi_driver_sensor.h\"\n#include \"ruuvi_interface_adc.h\"\n#include \"ruuvi_interface_adc_mcu.h\"\n#include \"ruuvi_interface_communication_radio.h\"\n#include \"ruuvi_interface_log.h\"\n#include \"ruuvi_interface_scheduler.h\"\n#include \"ruuvi_interface_rtc.h\"\n#include \"ruuvi_interface_timer.h\"\n#include \"task_adc.h\"\n#include \"task_led.h\"\n\n#include &lt;stddef.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;inttypes.h&gt;\n\nRUUVI_PLATFORM_TIMER_ID_DEF(adc_timer);\nstatic ruuvi_driver_sensor_t adc_sensor = {0};\nstatic volatile uint64_t t_sample = 0;\nstatic volatile float droop = 0;\nstatic volatile float after_tx = 0;\n\n\/* Use these functions for using ADC at regular, timed intervals\n * Remember to start the timer at init\n *\/\n\/\/handler for scheduled accelerometer event\nstatic void task_adc_scheduler_sample(void *p_event_data, uint16_t event_size)\n{\n  ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n\n  \/\/ Take new sample\n  status |= task_adc_sample();\n  \/\/ Log warning if adc sampling failed.\n  RUUVI_DRIVER_ERROR_CHECK(status, ~RUUVI_DRIVER_ERROR_FATAL);\n}\n\n\/\/ Timer callback, schedule event here or execute it right away if it's timing-critical\nstatic void task_adc_timer_cb(void* p_context)\n{\n  ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n  ruuvi_interface_adc_data_t rest;\n  \/\/ Take new ADC sample\n  status |= task_adc_sample();\n\n  \/\/ Read new sample\n  status |= adc_sensor.data_get(&amp;rest);\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Subtract active sample from rest sample\n  droop = rest.adc_v - after_tx;\n  if(0.0 &gt; droop) { droop = 0.0; }\n}\n\n\n\/\/ Callback for radio event. Sample voltage under load, schedule new measurement\nstatic void task_adc_trigger_on_radio\n(const ruuvi_interface_communication_radio_activity_evt_t evt)\n{\n\n  \/\/ If event is after radio activity\n  if(RUUVI_INTERFACE_COMMUNICATION_RADIO_AFTER == evt)\n  {\n    t_sample = ruuvi_platform_rtc_millis();\n    task_adc_sample();\n\n    \/\/ Read radio-synched ADC sample\n    ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n    ruuvi_interface_adc_data_t active;\n    status |= adc_sensor.data_get(&amp;active);\n    RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n    after_tx = active.adc_v;\n    ruuvi_platform_timer_start(adc_timer, APPLICATION_BATTERY_DROOP_DELAY_MS);\n  }\n}\n\n\nstatic ruuvi_driver_status_t task_adc_configure(void)\n{\n  ruuvi_driver_sensor_configuration_t config;\n  config.samplerate    = APPLICATION_ADC_SAMPLERATE;\n  config.resolution    = APPLICATION_ADC_RESOLUTION;\n  config.scale         = APPLICATION_ADC_SCALE;\n  config.dsp_function  = APPLICATION_ADC_DSPFUNC;\n  config.dsp_parameter = APPLICATION_ADC_DSPPARAM;\n  config.mode          = APPLICATION_ADC_MODE;\n  if(NULL == adc_sensor.data_get) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n  return adc_sensor.configuration_set(&amp;adc_sensor, &amp;config);\n}\n\nruuvi_driver_status_t task_adc_init(void)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  ruuvi_driver_bus_t bus = RUUVI_DRIVER_BUS_NONE;\n  uint8_t handle = RUUVI_INTERFACE_ADC_AINVDD;\n\n  \/\/ Initialize timer for adc task.\n  \/\/ Note: the timer is not started.\n  ruuvi_interface_timer_mode_t mode = RUUVI_INTERFACE_TIMER_MODE_SINGLE_SHOT;\n  err_code |= ruuvi_platform_timer_create(&amp;adc_timer, mode, task_adc_timer_cb);\n\n  err_code |= ruuvi_interface_adc_mcu_init(&amp;adc_sensor, bus, handle);\n  RUUVI_DRIVER_ERROR_CHECK(err_code, RUUVI_DRIVER_SUCCESS);\n\n  if(RUUVI_DRIVER_SUCCESS == err_code)\n  {\n    err_code |= task_adc_configure();\n\n    ruuvi_interface_communication_radio_activity_callback_set\n    (task_adc_trigger_on_radio);\n\n    return err_code;\n  }\n\n  \/\/ Return error if ADC could not be configured\n  return RUUVI_DRIVER_ERROR_NOT_FOUND;\n}\n\n\nruuvi_driver_status_t task_adc_sample(void)\n{\n  if(NULL == adc_sensor.mode_set) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n  uint8_t mode = RUUVI_DRIVER_SENSOR_CFG_SINGLE;\n  return adc_sensor.mode_set(&amp;mode);\n}\n\nruuvi_driver_status_t task_adc_data_get(ruuvi_interface_adc_data_t* const data)\n{\n  if(NULL == data) { return RUUVI_DRIVER_ERROR_NULL; }\n  if(NULL == adc_sensor.data_get) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  \/\/ Take new sample\n  task_adc_sample();\n  \/\/ Get latest data\n  adc_sensor.data_get(data);\n  \/\/ Fill reserved field with after tx, droop data\n  data-&gt;reserved0 = after_tx;\n  data-&gt;reserved1 = droop;\n\n  return err_code;\n}\n<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/b8f30570531edbb5af70e3a35954dafb\/raw\/e8bc45740cf0bc8a33a5428fbbc659753a976d1b\/ojousima.nrf52_batterytest.c_task_adc.c\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Wir haben die Logik zur Auswahl des Messmodus entfernt und <em>task_adc_data_get<\/em> so konfiguriert, dass der <strong>ADC<\/strong> genau dann gemessen wird, wenn Daten in Zeile 134 angefordert werden. Dieses Verhalten \u00e4hnelt der Ruuvi-Firmware 1.x und 2.x. Wir geben hier auch die zuvor gemessenen und gespeicherten Werte <em>after tx<\/em> und <em>droop<\/em> zur\u00fcck.  <\/p>\n\n<p class=\"wp-block-paragraph\">In <em>task_advertisement.c<\/em> entfernen wir die <a href=\"https:\/\/ruuvi.com\/ruuvi-firmware-part-9-bluetooth-broadcasting\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Ruuvi Endpoints<\/em><\/a> und f\u00fcgen <strong>0xBA<\/strong> als unser eigenes <strong>APPLICATION_DATA_FORMAT<\/strong> hinzu. Der eigene Endpoint <em>app_endpoint_ba<\/em> wird in Zeile 85 aufgerufen und die kodierten Daten werden in Zeile 86 gepuffert, um gesendet zu werden<em>.<\/em> <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Ruuvi Firmware 3.x advertisement tasks.\n *\n * License: BSD-3\n * Author: Otso Jousimaa &lt;otso@ojousima.net&gt;\n **\/\n\n#include \"application_config.h\"\n#include \"app_endpoint_ba.h\"\n#include \"ruuvi_boards.h\"\n#include \"ruuvi_driver_error.h\"\n#include \"ruuvi_interface_adc.h\"\n#include \"ruuvi_interface_communication_ble4_advertising.h\"\n#include \"ruuvi_interface_communication_radio.h\"\n#include \"ruuvi_interface_environmental.h\"\n#include \"ruuvi_interface_scheduler.h\"\n#include \"ruuvi_interface_timer.h\"\n#include \"task_adc.h\"\n#include \"task_advertisement.h\"\n#include \"task_environmental.h\"\n\nRUUVI_PLATFORM_TIMER_ID_DEF(advertisement_timer);\nstatic ruuvi_interface_communication_t channel;\n\n\/\/handler for scheduled advertisement event\nstatic void task_advertisement_scheduler_task(void *p_event_data, uint16_t event_size)\n{\n  \/\/ Update BLE data\n  task_advertisement_send_ba();\n\n}\n\n\/\/ Timer callback, schedule advertisement event here.\nstatic void task_advertisement_timer_cb(void* p_context)\n{\n  ruuvi_platform_scheduler_event_put(NULL, 0, task_advertisement_scheduler_task);\n}\n\nruuvi_driver_status_t task_advertisement_init(void)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  err_code |= ruuvi_interface_communication_ble4_advertising_init(&amp;channel);\n  err_code |= ruuvi_interface_communication_ble4_advertising_tx_interval_set\n  (APPLICATION_ADVERTISING_INTERVAL);\n\n  int8_t target_power = APPLICATION_ADVERTISING_POWER;\n  err_code |= ruuvi_interface_communication_ble4_advertising_tx_power_set\n  (&amp;target_power);\n\n  err_code |= ruuvi_interface_communication_ble4_advertising_manufacturer_id_set\n  (RUUVI_BOARD_BLE_MANUFACTURER_ID);\n\n  err_code |= ruuvi_platform_timer_create(&amp;advertisement_timer,\n                                           RUUVI_INTERFACE_TIMER_MODE_REPEATED,\n                                           task_advertisement_timer_cb);\n  err_code |= ruuvi_platform_timer_start(advertisement_timer,\n                                         APPLICATION_ADVERTISING_INTERVAL);\n  return err_code;\n}\n\nruuvi_driver_status_t task_advertisement_send_ba(void)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  static uint16_t sequence = 0;\n  sequence++;\n\n  ruuvi_interface_adc_data_t battery;\n  ruuvi_interface_environmental_data_t environmental;\n\n  \/\/ Get data from sensors\n  err_code |= task_environmental_data_get(&amp;environmental);\n  err_code |= task_adc_data_get(&amp;battery);\n\n  app_endpoint_ba_data_t data;\n  data.humidity_rh = environmental.humidity_rh;\n  data.temperature_c = environmental.temperature_c;\n  data.simple_v = battery.adc_v;\n  data.radio_v = battery.reserved0;\n  data.droop_v  = battery.reserved1;\n  data.measurement_count = sequence;\n\n\n  ruuvi_interface_communication_message_t message;\n  message.data_length = APP_ENDPOINT_BA_DATA_LENGTH;\n  app_endpoint_ba_encode(message.data, &amp;data, RUUVI_DRIVER_FLOAT_INVALID);\n  err_code |= channel.send(&amp;message);\n\n  return err_code;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/15bbeed108f435f6c1b5a515da6ed102\/raw\/eb4d7d399d54fd0e32a7e652eac168c8fda878ce\/ojousima.nrf52_batterytest.c_task_advertisement.c\">Rohdaten anzeigen<\/a><\/p>\n\n<h2 class=\"wp-block-heading\">Erstellen eines neuen Datenformats<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir nehmen das <a href=\"https:\/\/github.com\/ruuvi\/ruuvi-sensor-protocols\" target=\"_blank\" rel=\"noreferrer noopener\">Ruuvi-Datenformat 5<\/a> als Basis und erstellen <em>app_endpoint_ba.c<\/em> und -.h aus dem vorherigen Code.<\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Application endpoint helper.\n * Defines necessary data for creating application spceific BA broadcast\n *\n * License: BSD-3\n * Author: Otso Jousimaa &lt;otso@ojousima.net&gt;\n *\/\n\n#ifndef APP_ENDPOINT_BA_H\n#define APP_ENDPOINT_BA_H\n#include \"ruuvi_endpoints.h\"\n\n#define APP_ENDPOINT_BA_DESTINATION                 0xBA\n#define APP_ENDPOINT_BA_VERSION                     0\n#define APP_ENDPOINT_BA_DATA_LENGTH                 14\n\n#define APP_ENDPOINT_BA_OFFSET_HEADER               0\n#define APP_ENDPOINT_BA_OFFSET_VERSION              1\n#define APP_ENDPOINT_BA_OFFSET_TEMPERATURE_MSB      2\n#define APP_ENDPOINT_BA_OFFSET_TEMPERATURE_LSB      3\n#define APP_ENDPOINT_BA_OFFSET_HUMIDITY_MSB         4\n#define APP_ENDPOINT_BA_OFFSET_HUMIDITY_LSB         5\n#define APP_ENDPOINT_BA_OFFSET_SIMPLE_MSB           6\n#define APP_ENDPOINT_BA_OFFSET_SIMPLE_LSB           7\n#define APP_ENDPOINT_BA_OFFSET_RADIO_MSB            8\n#define APP_ENDPOINT_BA_OFFSET_RADIO_LSB            9\n#define APP_ENDPOINT_BA_OFFSET_DROOP_MSB            10\n#define APP_ENDPOINT_BA_OFFSET_DROOP_LSB            11\n#define APP_ENDPOINT_BA_OFFSET_SEQUENCE_COUNTER_MSB 12\n#define APP_ENDPOINT_BA_OFFSET_SEQUENCE_COUNTER_LSB 13\n\n\n\ntypedef struct{\n  float humidity_rh;\n  float pressure_pa;\n  float temperature_c;\n  float simple_v;\n  float radio_v;\n  float droop_v;\n  uint16_t measurement_count;\n}app_endpoint_ba_data_t;\n\n\/**\n * Encode given data to given buffer in app format BA.\n *\n * parameter data: uint8_t array with length of 24 bytes.\n * parameter data: Struct containing all necessary information for\n *                 encoding the data into buffer\n * parameter invalid: A float which signals that given data point is invalid.\n *\/\nruuvi_endpoint_status_t app_endpoint_ba_encode(uint8_t* const buffer,\n                                               const app_endpoint_ba_data_t* data,\n                                               const float invalid);\n\n\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/a2cac0cf70f7974c1a6beda86eb7d885\/raw\/dd36ab2ffd139ef9febcaeab775704e5de153e41\/ojousima.nrf52_batterytest.c_app_endpoint_ba.h\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Unser Datenformat-Header hat die Datenversion an Index 1, falls wir das Format in Zukunft \u00e4ndern m\u00f6chten. Temperatur und Luftfeuchtigkeit werden auf die gleiche Weise wie in Datenformat 5 kodiert. Spannungen werden als uint16_t Millivolt kodiert. Jetzt haben wir unser Datenformat definiert, die Implementierung befindet sich in der .c-Datei unten<\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Application endpoint helper.\n * Defines necessary data for creating application spceific BA broadcast\n *\n * License: BSD-3\n * Author: Otso Jousimaa &lt;otso@ojousima.net&gt;\n *\/\n\n#include \"app_endpoint_ba.h\"\n#include \"ruuvi_endpoints.h\"\n#include &lt;stddef.h&gt;\n#include &lt;stdbool.h&gt;\n#include &lt;string.h&gt;\n#include &lt;math.h&gt;\n\nruuvi_endpoint_status_t app_endpoint_ba_encode(uint8_t* const buffer,\n                                               const app_endpoint_ba_data_t* data,\n                                               const float invalid)\n{\n  if(NULL == buffer  || NULL == data) { return RUUVI_ENDPOINT_ERROR_NULL; }\n\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_HEADER]  = APP_ENDPOINT_BA_DESTINATION;\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_VERSION] = APP_ENDPOINT_BA_VERSION;\n\n  \/\/ HUMIDITY\n  uint16_t humidity = 0;\n  if(invalid != data-&gt;humidity_rh &amp;&amp; 0 &lt; data-&gt;humidity_rh)\n  {\n    \/\/Humidity (16bit unsigned) in 0.0025% (0-163.83% range, though realistically 0-100%)\n     humidity = (uint16_t)(data-&gt;humidity_rh*400);\n  }\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_HUMIDITY_MSB] = (humidity &gt;&gt; 8);\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_HUMIDITY_LSB] = humidity &amp; 0xFF;\n\n  \/\/ Temperature is in 0.005 degrees\n  int16_t temperature = 0;\n  if(invalid != data-&gt;temperature_c)\n  {\n    temperature = (int16_t)(data-&gt;temperature_c * 200 );\n  }\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_TEMPERATURE_MSB] = (temperature &gt;&gt; 8);\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_TEMPERATURE_LSB] = (temperature &amp; 0xFF);\n\n  \/\/ voltages\n  uint16_t simple_v = 0;\n  uint16_t radio_v = 0;\n  uint16_t droop_v = 0;\n  if(invalid != data-&gt;simple_v)\n  {\n    \/\/ Convert to millivolts\n    simple_v = (data-&gt;simple_v &gt; 0) ? data-&gt;simple_v * 1000 : 0;\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_SIMPLE_MSB] = (simple_v &gt;&gt; 8);\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_SIMPLE_LSB] = (simple_v &amp; 0xFF);\n  }\n\n  if(invalid != data-&gt;radio_v)\n  {\n    \/\/ Convert to millivolts\n    radio_v = (data-&gt;radio_v &gt; 0) ? data-&gt;radio_v * 1000 : 0;\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_RADIO_MSB] = (radio_v &gt;&gt; 8);\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_RADIO_LSB] = (radio_v &amp; 0xFF);\n  }\n\n  if(invalid != data-&gt;droop_v)\n  {\n    \/\/ Convert to millivolts\n    droop_v = (data-&gt;droop_v &gt; 0) ? data-&gt;droop_v * 1000 : 0;\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_DROOP_MSB] = (droop_v &gt;&gt; 8);\n    buffer&#091;APP_ENDPOINT_BA_OFFSET_DROOP_LSB] = (droop_v &amp; 0xFF);\n  }\n\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_SEQUENCE_COUNTER_MSB] = (data-&gt;measurement_count &gt;&gt; 8);\n  buffer&#091;APP_ENDPOINT_BA_OFFSET_SEQUENCE_COUNTER_LSB] = (data-&gt;measurement_count &amp; 0xFF);\n\n  return RUUVI_ENDPOINT_SUCCESS;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/889c02ee27e1ee9d499d514b1d14a2d4\/raw\/c0d785fd10a66cdf9d4d651beace5962653080fa\/ojousima.nrf52_batterytest.c_app_endpoint_ba.c\">Rohdaten anzeigen<\/a><\/p>\n\n<h2 class=\"wp-block-heading\">Der Stromverbrauch sollte ausreichen, um die Batterie innerhalb eines angemessenen Zeitrahmens zu entleeren<\/h2>\n\n<p class=\"wp-block-paragraph\">Da wir weder Beschleunigungssensor noch Taste verwenden, entfernen wir die Beschleunigungssensor- und Tasten-Tasks aus dem Projekt. Schlie\u00dflich lassen wir die gr\u00fcne LED nach der Initialisierung eingeschaltet, um eine ausreichende Stromentnahme aus der Batterie zu erzeugen. Die LEDs verbrauchen jeweils etwa 1 <em>mA<\/em>, sodass wir bei einer konstanten Entnahme von 1 <em>mA<\/em> maximal 1.000 Stunden \u2013 oder 42 Tage \u2013 Laufzeit f\u00fcr unseren Test erwarten k\u00f6nnen.  <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * Ruuvi Firmware 3.x code. Reads the sensors onboard RuuviTag and broadcasts the sensor data in a manufacturer specific format.\n *\n * License: BSD-3\n * Author: Otso Jousimaa &lt;otso@ojousima.net&gt;\n **\/\n\n#include \"application_config.h\"\n#include \"ruuvi_interface_gpio.h\"\n#include \"ruuvi_interface_log.h\"\n#include \"ruuvi_interface_scheduler.h\"\n#include \"ruuvi_interface_yield.h\"\n#include \"ruuvi_boards.h\"\n#include \"task_adc.h\"\n#include \"task_advertisement.h\"\n#include \"task_environmental.h\"\n#include \"task_led.h\"\n#include \"task_nfc.h\"\n#include \"task_power.h\"\n#include \"task_rtc.h\"\n#include \"task_scheduler.h\"\n#include \"task_spi.h\"\n#include \"task_timer.h\"\n#include \"test_sensor.h\"\n\n#include &lt;stdio.h&gt;\n\nint main(void)\n{\n  \/\/ Init logging\n  ruuvi_driver_status_t status = RUUVI_DRIVER_SUCCESS;\n  status |= ruuvi_platform_log_init(APPLICATION_LOG_LEVEL);\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Init yield\n  status |= ruuvi_platform_yield_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Init GPIO\n  status |= ruuvi_platform_gpio_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize LED gpio pins, turn RED led on.\n  status |= task_led_init();\n  status |= task_led_write(RUUVI_BOARD_LED_RED, TASK_LED_ON);\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize SPI\n  status |= task_spi_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize RTC, timer and scheduler\n  status |= task_rtc_init();\n  status |= task_timer_init();\n  status |= task_scheduler_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize power\n  status |= task_power_dcdc_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize nfc\n  status |= task_nfc_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize ADC\n  status |= task_adc_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize environmental- nRF52 will return ERROR NOT SUPPORTED on RuuviTag basic\n  \/\/ if DSP was configured, log warning\n  status |= task_environmental_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Initialize BLE\n  status |= task_advertisement_init();\n  RUUVI_DRIVER_ERROR_CHECK(status, RUUVI_DRIVER_SUCCESS);\n\n  \/\/ Turn RED led off. Turn GREEN LED on if no errors occured\n  status |= task_led_write(RUUVI_BOARD_LED_RED, TASK_LED_OFF);\n  if(RUUVI_DRIVER_SUCCESS == status)\n  {\n    status |= task_led_write(RUUVI_BOARD_LED_GREEN, TASK_LED_ON);\n    ruuvi_platform_delay_ms(1000);\n  }\n\n  while (1)\n  {\n    \/\/ Turn off activity led\n    status = task_led_write(RUUVI_BOARD_LED_RED, !RUUVI_BOARD_LEDS_ACTIVE_STATE);\n    \/\/ Sleep\n    status |= ruuvi_platform_yield();\n    \/\/ Turn on activity led\n    status |= task_led_write(RUUVI_BOARD_LED_RED, RUUVI_BOARD_LEDS_ACTIVE_STATE);\n    \/\/ Execute scheduled tasks\n     status |= ruuvi_platform_scheduler_execute();\n    \/\/ Reset only on fatal error\n    RUUVI_DRIVER_ERROR_CHECK(status, ~RUUVI_DRIVER_ERROR_FATAL);\n  }\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/43bc3ffa2d8f14fafad13a1d3304d49f\/raw\/48aaed29f327a7e0019905f20d458c359d4a6a4b\/ojousima.nrf52_batterytest.c_main.c\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Das war&#8217;s f\u00fcr die Firmware! Schauen wir mal, wie es im Power Profiler aussieht: <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"686\" src=\"https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-1024x686.png\" alt=\"Leistungsprofil f&#xFC;r den RuuviTag\" class=\"wp-image-2960\" srcset=\"https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-1024x686.png 1024w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-450x302.png 450w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-768x515.png 768w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-1536x1029.png 1536w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2048x1372.png 2048w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-600x402.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Unser Tag verbraucht etwa 1,1 mA bei 3,1 V<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"695\" src=\"https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-1024x695.png\" alt=\"Leistungsprofil mit Verbrauchsanzeige\" class=\"wp-image-2961\" srcset=\"https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-1024x695.png 1024w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-450x305.png 450w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-768x521.png 768w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-1536x1042.png 1536w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-2048x1389.png 2048w, https:\/\/ruuvi.com\/i\/u\/graph-power-profile-nrf-2-600x407.png 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Der Verbrauch betr\u00e4gt etwa 0,61 mA bei 2,5 V<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Es ist wichtig, zwei Dinge zu beachten: Unsere konstante Stromentnahme ist doch nicht so konstant, da der Strom durch die <strong>LED<\/strong> abnimmt, wenn unsere Batteriespannung sinkt. Ein weiterer wichtiger Punkt ist, dass unsere Funk\u00fcbertragungen bei niedrigerer Spannung aufgrund des <strong>DC\/DC<\/strong>-Wandlers, der dem Funk konstante Leistung liefern muss, deutlich mehr Strom verbrauchen. <\/p>\n\n<h2 class=\"wp-block-heading\">Schreiben eines Interpreters f\u00fcr die Daten<\/h2>\n\n<p class=\"wp-block-paragraph\">Da ich bei jeder Gelegenheit gerne etwas Neues lerne, implementieren wir den Interpreter mit <a href=\"https:\/\/www.typescriptlang.org\" target=\"_blank\" rel=\"noreferrer noopener\">Typescript<\/a>. Wir folgen <a href=\"https:\/\/itnext.io\/step-by-step-building-and-publishing-an-npm-typescript-package-44fe7164964c\" target=\"_blank\" rel=\"noreferrer noopener\">Carl-Johan Kihls Tutorial<\/a>, wie man ein Typescript-Modul f\u00fcr <a href=\"https:\/\/www.npmjs.com\" target=\"_blank\" rel=\"noreferrer noopener\">NPM<\/a> erstellt. Bald haben wir einen Interpreter, komplett mit Tests. Die Quellen befinden sich unter <a href=\"https:\/\/github.com\/ojousima\/ojousima.ruuvi_endpoints.ts\" target=\"_blank\" rel=\"noreferrer noopener\">ojousima.ruuvi_endpoints.ts<\/a>.   <\/p>\n\n<pre class=\"wp-block-code\"><code>import { BatteryBroadcast } from '.\/batterybroadcast';\n\nconst versionStart     = 1;\nconst versionEnd       = versionStart +1;\nconst temperatureStart = versionEnd;\nconst temperatureEnd   = temperatureStart + 2;\nconst humidityStart    = temperatureEnd;\nconst humidityEnd      = humidityStart + 2;\nconst simpleStart      = humidityEnd;\nconst simpleEnd        = simpleStart + 2;\nconst radioStart       = simpleEnd;\nconst radioEnd         = radioStart + 2;\nconst droopStart       = radioEnd;\nconst droopEnd         = droopStart + 2;\nconst measurementStart = droopEnd;\nconst measurementEnd   = measurementStart + 2;\n\nexport const dfbaparser = (data: Uint8Array): BatteryBroadcast =&gt; {\n  const robject: BatteryBroadcast = new BatteryBroadcast();\n  if (0xBA !== data&#091;0]) {\n    throw new Error('Not DF BA data');\n  }\n\n  robject.dataFormat = 0xBA;\n\n  const version = data&#091;versionStart];\n  robject.version = version;\n\n  const temperatureBytes = data.slice(temperatureStart, temperatureEnd);\n  let temperature = temperatureBytes&#091;0] * 256 + temperatureBytes&#091;1];\n  \/\/ two's complement\n  if (temperature &gt; 32767) {\n    temperature -= 65536;\n  }\n  \/\/ Temperature is in units of 0.005 C -&gt; divide by 200\n  robject.temperatureC = temperature \/ 200;\n\n  const humidityBytes = data.slice(humidityStart, humidityEnd);\n  let humidity = humidityBytes&#091;0] * 256 + humidityBytes&#091;1];\n  \/\/ Humidity is in units of 0.0025 % -&gt; divide by 400\n  robject.humidityRh = humidity \/ 400;\n\n  const simpleBytes = data.slice(simpleStart, simpleEnd);\n  let simple = simpleBytes&#091;0] * 256 + simpleBytes&#091;1];\n  \/\/ two's complement\n  if (simple &gt; 32767) {\n    simple -= 65536;\n  } \n  robject.simpleVoltageV = simple \/ 1000;\n\n  const radioBytes = data.slice(radioStart, radioEnd);\n  let radio = radioBytes&#091;0] * 256 + radioBytes&#091;1];\n  \/\/ two's complement\n  if (radio &gt; 32767) {\n    radio -= 65536;\n  } \n  robject.radioVoltageV = radio \/ 1000;\n\n  const droopBytes = data.slice(droopStart, droopEnd);\n  let droop = droopBytes&#091;0] * 256 + droopBytes&#091;1];\n  \/\/ two's complement\n  if (droop &gt; 32767) {\n    droop -= 65536;\n  } \n  robject.droopVoltageV = droop \/ 1000;\n\n  const measurementBytes = data.slice(measurementStart, measurementEnd);\n  let measurement = measurementBytes&#091;0] * 256 + measurementBytes&#091;1];\n  robject.measurementSequence = measurement;\n\n  return robject;\n};<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/5dea5ea7e7fe76d11d9cf43ba33eba11\/raw\/3d737a0150632c6637814883b7770ff1fe7b834e\/ojousima_endpoint_ba.ts\">Rohdaten anzeigen<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Unser Interpreter hat nichts Kompliziertes, wir parsen einfach die Bytes aus dem Array und kehren das Packing um, das im C-Code vorgenommen wurde.<\/p>\n\n<h2 class=\"wp-block-heading\">Gateway-Software<\/h2>\n\n<p class=\"wp-block-paragraph\">Unsere Gateway-Software wird mit NodeJS implementiert und verwendet:<\/p>\n\n<ul class=\"wp-block-list\"><li>ojousima.ruuvi_endpoints.ts wie oben geschrieben<\/li><li><a href=\"https:\/\/node-influx.github.io\" target=\"_blank\" rel=\"noreferrer noopener\">node-influx<\/a><\/li><li><a href=\"https:\/\/github.com\/noble\/noble\" target=\"_blank\" rel=\"noreferrer noopener\">noble<\/a><\/li><\/ul>\n\n<p class=\"wp-block-paragraph\">Der K\u00fcrze halber gehen wir nicht auf die Details des Gateways ein. Die Grundidee ist einfach genug: Wir h\u00f6ren mit Noble die BLE-Advertisements ab, pr\u00fcfen, ob die Daten von Ruuvi Innovations stammen und ob sie im <strong>0xBA<\/strong>-Format vorliegen. Falls ja, parsen wir die Daten mit <em>ojousima.ruuvi_endpoints.ts<\/em> und leiten sie mit <em>node-influx<\/em> an <em>InfluxDB<\/em> weiter.  <\/p>\n\n<p class=\"wp-block-paragraph\">F\u00fcr diejenigen, die daran interessiert sind, das Experiment zu replizieren, befinden sich die Quellen f\u00fcr das Gateway <a href=\"https:\/\/github.com\/ojousima\/ojousima.ble_influx_gw.ts\/tree\/raspberrypi\" target=\"_blank\" rel=\"noreferrer noopener\">hier<\/a>. Es sollte beachtet werden, dass das Projekt von <em>Noble<\/em> abh\u00e4ngt, und <em>Noble<\/em> hat ab Oktober 2018 eine schlechte Unterst\u00fctzung f\u00fcr <em>NodeJS 10.x<\/em>. Verwende <a href=\"https:\/\/github.com\/creationix\/nvm\" target=\"_blank\" rel=\"noreferrer noopener\">NVM<\/a>, um das Programm unter <em>NodeJS 8.12<\/em> auszuf\u00fchren.  <\/p>\n\n<h2 class=\"wp-block-heading\">Server<\/h2>\n\n<p class=\"wp-block-paragraph\">Unser Server wird ein Digital Ocean Droplet live.ojousima.net sein. Das Droplet wurde mit 2 GB RAM + 50 GB SSD dimensioniert, was mehr als ausreichend f\u00fcr die Datenmenge ist, die wir erwarten zu sammeln. Wir richten <a href=\"https:\/\/docs.influxdata.com\/influxdb\/v1.6\/introduction\/installation\/\" target=\"_blank\" rel=\"noreferrer noopener\">InfluxDB<\/a> und <a href=\"http:\/\/docs.grafana.org\/installation\/debian\/\" target=\"_blank\" rel=\"noreferrer noopener\">Grafana<\/a> auf dem Server ein und \u00e4ndern die Passw\u00f6rter, um zu vermeiden, dass Spa\u00dfv\u00f6gel mit unserem Experiment herumspielen \ud83d\ude09  <\/p>\n\n<p class=\"wp-block-paragraph\">Wie beim Gateway gehen wir hier nicht ins Detail. Schau dir \u201e<a href=\"https:\/\/ruuvi.com\/de\/einrichtung-eines-raspberry-pi-als-ruuvi-gateway\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Raspberry Pi 3 als Ruuvi Gateway einrichten<\/em><\/a><em>\u201c<\/em> an \u2013 als allgemeine Anleitung zu InfluxDB + Grafana unter Debian. <\/p>\n\n<h2 class=\"wp-block-heading\">Testen<\/h2>\n\n<p class=\"wp-block-paragraph\">Jetzt haben wir die Software gekl\u00e4rt. Die Hardware ist der einfache Teil \u2013 wir flashen die Firmware auf 16 RuuviTags, best\u00fccken 8 davon mit Standardbatterien und 8 mit Extended-Range-Batterien. <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1919\" height=\"2560\" src=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled.jpg\" alt=\"Tags und Batterien\" class=\"wp-image-2962\" srcset=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled.jpg 1919w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled-337x450.jpg 337w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled-768x1025.jpg 768w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled-1151x1536.jpg 1151w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled-1535x2048.jpg 1535w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-batteries-scaled-600x800.jpg 600w\" sizes=\"auto, (max-width: 1919px) 100vw, 1919px\" \/><figcaption>Tags + Batterien<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-1024x768.jpg\" alt=\"Tags im Gefrierschrank\" class=\"wp-image-2963\" srcset=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-1024x768.jpg 1024w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-450x337.jpg 450w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-768x576.jpg 768w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-1536x1151.jpg 1536w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-2048x1535.jpg 2048w, https:\/\/ruuvi.com\/i\/u\/ruuvi-tags-freezer-600x450.jpg 600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Erste Gruppe im hinteren Teil eines Gefrierschranks<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Jetzt m\u00fcssen wir nur noch abwarten und hin und wieder auf <a href=\"http:\/\/live.ojousima.net\/d\/_IZ1YIamz\/overview?panelId=6&amp;orgId=1&amp;from=1540988567130&amp;to=1546280567131&amp;tab=general\" target=\"_blank\" rel=\"noreferrer noopener\">live.ojousima.net<\/a> nach den Daten schauen.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>K\u00fcrzlich haben wir bei der Entwicklung der offiziellen Ruuvi-Firmware etwas Interessantes bemerkt: Die Batteriespannung zeigt einen erheblichen Spannungseinbruch bei der Funk\u00fcbertragung. Diese Entdeckung rechtfertigt weitere Untersuchungen zur Messung des Batteriestands. Hier stellen wir den allgemeinen Arbeitsablauf vor. Bitte beachte, dass wir unsere Arbeit auf der Firmware-Version 3.140-alpha basieren \u2013 die hier gegebenen Codebeispiele funktionieren m\u00f6glicherweise [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":135816,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[324],"tags":[],"class_list":["post-135814","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ruuvi-software-artikel"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi<\/title>\n<meta name=\"description\" content=\"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi\" \/>\n<meta property=\"og:description\" content=\"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/\" \/>\n<meta property=\"og:site_name\" content=\"Ruuvi\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ruuvi.cc\" \/>\n<meta property=\"article:published_time\" content=\"2018-11-08T14:05:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-11T05:48:56+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ruuvi.com\/i\/u\/graph-overview.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2149\" \/>\n\t<meta property=\"og:image:height\" content=\"1061\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Otso Jousimaa\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ruuvicom\" \/>\n<meta name=\"twitter:site\" content=\"@ruuvicom\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Otso Jousimaa\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"21\u00a0Minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/\"},\"author\":{\"name\":\"Otso Jousimaa\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"headline\":\"Eigenes Ruuvi-Datenformat an einem Tag\",\"datePublished\":\"2018-11-08T14:05:00+00:00\",\"dateModified\":\"2026-06-11T05:48:56+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/\"},\"wordCount\":1144,\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/graph-overview.png\",\"articleSection\":[\"Ruuvi-Software-Artikel\"],\"inLanguage\":\"de\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/\",\"name\":\"Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/graph-overview.png\",\"datePublished\":\"2018-11-08T14:05:00+00:00\",\"dateModified\":\"2026-06-11T05:48:56+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"description\":\"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/graph-overview.png\",\"contentUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/graph-overview.png\",\"width\":2149,\"height\":1061,\"caption\":\"Graph mit Spannungs\u00fcbersicht\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/eigenes-ruuvi-datenformat-an-einem-tag\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/front\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Eigenes Ruuvi-Datenformat an einem Tag\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#website\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/\",\"name\":\"Ruuvi\",\"description\":\"Measure Your World\",\"potentialAction\":[],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\",\"name\":\"Otso Jousimaa\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g\",\"caption\":\"Otso Jousimaa\"},\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/author\\\/ojousima\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi","description":"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/","og_locale":"de_DE","og_type":"article","og_title":"Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi","og_description":"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.","og_url":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/","og_site_name":"Ruuvi","article_publisher":"https:\/\/www.facebook.com\/ruuvi.cc","article_published_time":"2018-11-08T14:05:00+00:00","article_modified_time":"2026-06-11T05:48:56+00:00","og_image":[{"width":2149,"height":1061,"url":"https:\/\/ruuvi.com\/i\/u\/graph-overview.png","type":"image\/png"}],"author":"Otso Jousimaa","twitter_card":"summary_large_image","twitter_creator":"@ruuvicom","twitter_site":"@ruuvicom","twitter_misc":{"Verfasst von":"Otso Jousimaa","Gesch\u00e4tzte Lesezeit":"21\u00a0Minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#article","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/"},"author":{"name":"Otso Jousimaa","@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"headline":"Eigenes Ruuvi-Datenformat an einem Tag","datePublished":"2018-11-08T14:05:00+00:00","dateModified":"2026-06-11T05:48:56+00:00","mainEntityOfPage":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/"},"wordCount":1144,"image":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/graph-overview.png","articleSection":["Ruuvi-Software-Artikel"],"inLanguage":"de"},{"@type":"WebPage","@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/","url":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/","name":"Eigenes Ruuvi-Datenformat an einem Tag - Ruuvi","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#primaryimage"},"image":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/graph-overview.png","datePublished":"2018-11-08T14:05:00+00:00","dateModified":"2026-06-11T05:48:56+00:00","author":{"@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"description":"Ruuvi-Firmware-Entwicklung: Planung ist der Schl\u00fcssel zum Erfolg beim Umgang mit verschiedenen Methoden zur Batteriespannungsmessung.","breadcrumb":{"@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#primaryimage","url":"https:\/\/ruuvi.com\/i\/u\/graph-overview.png","contentUrl":"https:\/\/ruuvi.com\/i\/u\/graph-overview.png","width":2149,"height":1061,"caption":"Graph mit Spannungs\u00fcbersicht"},{"@type":"BreadcrumbList","@id":"https:\/\/ruuvi.com\/de\/eigenes-ruuvi-datenformat-an-einem-tag\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ruuvi.com\/de\/front\/"},{"@type":"ListItem","position":2,"name":"Eigenes Ruuvi-Datenformat an einem Tag"}]},{"@type":"WebSite","@id":"https:\/\/ruuvi.com\/de\/#website","url":"https:\/\/ruuvi.com\/de\/","name":"Ruuvi","description":"Measure Your World","potentialAction":[],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00","name":"Otso Jousimaa","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fd52303e35b8b23c01cfeec7bb2636768de567cd33604f794ae86dd971e61645?s=96&d=mm&r=g","caption":"Otso Jousimaa"},"url":"https:\/\/ruuvi.com\/de\/author\/ojousima\/"}]}},"_links":{"self":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135814","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/comments?post=135814"}],"version-history":[{"count":1,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135814\/revisions"}],"predecessor-version":[{"id":135827,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135814\/revisions\/135827"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media\/135816"}],"wp:attachment":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media?parent=135814"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/categories?post=135814"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/tags?post=135814"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}