{"id":135681,"date":"2019-11-18T13:58:00","date_gmt":"2019-11-18T11:58:00","guid":{"rendered":"https:\/\/ruuvi.com\/ruuvi-firmware-neuen-sensor-hinzufuegen\/"},"modified":"2026-06-11T07:31:50","modified_gmt":"2026-06-11T04:31:50","slug":"ruuvi-firmware-neuen-sensor-hinzufuegen","status":"publish","type":"post","link":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/","title":{"rendered":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"500\" src=\"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png\" alt=\"TMP117 von Texas Instruments\" class=\"wp-image-4019\" srcset=\"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png 800w, https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments-450x281.png 450w, https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments-768x480.png 768w, https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments-600x375.png 600w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption><a href=\"https:\/\/www.ti.com\/product\/TMP117\">TMP117<\/a> von Texas Instruments<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Heute gehen wir durch, wie man einen neuen Sensor zur Ruuvi-Firmware hinzuf\u00fcgt. Dieser Beitrag baut auf der RuuviFW-Version 3.28.0 auf, die auf <a href=\"https:\/\/github.com\/ruuvi\/ruuvi.firmware.c\">GitHub<\/a> verf\u00fcgbar ist. Das Projekt wird mit Segger Embedded Studio Nordic Semiconductor Version 4.18 kompiliert. Die nRF SDK-Version ist nRF5_SDK_15.3.0_59ac345. Detaillierte Einrichtungsanweisungen <a href=\"https:\/\/ruuvi.com\/ruuvi-firmware-part-1-sleep\/\">findest du im Beitrag Ruuvi-Firmware \u2013 Teil 1<\/a>.    <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"802\" height=\"641\" src=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-architecture-1.png\" alt=\"Ruuvi-Firmware-Architektur\" class=\"wp-image-4020\" srcset=\"https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-architecture-1.png 802w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-architecture-1-450x360.png 450w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-architecture-1-768x614.png 768w, https:\/\/ruuvi.com\/i\/u\/ruuvi-firmware-architecture-1-600x480.png 600w\" sizes=\"auto, (max-width: 802px) 100vw, 802px\" \/><figcaption>Wir f\u00fcgen die gr\u00fcnen Abschnitte hinzu und \u00e4ndern die blau-gr\u00fcnen Verlaufsabschnitte, um den neuen Sensor zu unterst\u00fctzen.<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Sensor<\/h2>\n\n<p class=\"wp-block-paragraph\">Der Sensor, den wir hinzuf\u00fcgen, ist <a href=\"http:\/\/www.ti.com\/product\/TMP117\"><strong>TMP117<\/strong><\/a> von Texas Instruments. Es ist ein hochpr\u00e4ziser Temperatursensor mit \u00b10,1 \u00b0C absoluter Genauigkeit von \u201320 \u00b0C bis +50 \u00b0C.<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"900\" src=\"https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-1024x900.png\" alt=\"TMP117-Datenblatt\" class=\"wp-image-4021\" srcset=\"https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-1024x900.png 1024w, https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-450x395.png 450w, https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-768x675.png 768w, https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-1536x1349.png 1536w, https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet-600x527.png 600w, https:\/\/ruuvi.com\/i\/u\/tmp117-datasheet.png 1680w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><a href=\"https:\/\/www.ti.com\/lit\/ds\/symlink\/tmp117.pdf\">Lies das vollst\u00e4ndige Datenblatt.<\/a><\/figcaption><\/figure><\/div>\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Enabling research in wireless patient monitoring using TI sensors with the University of California\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/QQR1XTWh47M?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption>TMP117 ist ein digitaler Temperatursensor, der eine hohe Genauigkeit von \u00b10,1 \u00b0C bietet. Das reicht aus, um menschliche Patienten zu \u00fcberwachen. <\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\">Lass uns anfangen<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir arbeiten in diesem Blogbeitrag an einem noch nicht \u00f6ffentlichen Board mit dem Codenamen \u201eKaarle\u201c.<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"829\" height=\"1024\" src=\"https:\/\/ruuvi.com\/i\/u\/project-explorer-829x1024.png\" alt=\"Projekt-Explorer\" class=\"wp-image-4022\" srcset=\"https:\/\/ruuvi.com\/i\/u\/project-explorer-829x1024.png 829w, https:\/\/ruuvi.com\/i\/u\/project-explorer-364x450.png 364w, https:\/\/ruuvi.com\/i\/u\/project-explorer-768x948.png 768w, https:\/\/ruuvi.com\/i\/u\/project-explorer-600x741.png 600w, https:\/\/ruuvi.com\/i\/u\/project-explorer.png 878w\" sizes=\"auto, (max-width: 829px) 100vw, 829px\" \/><figcaption>Stelle sicher, dass du das Projekt mit Debug-Einstellungen und auf dem richtigen Board kompilierst.<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Low-Level-Schnittstelle: I2C-Bus<\/h2>\n\n<p class=\"wp-block-paragraph\">Um die Daten tats\u00e4chlich vom Sensor zu erhalten, m\u00fcssen wir die <strong>I2C<\/strong>-Schreib- und Lesefunktionen implementieren. Der Gro\u00dfteil der Arbeit ist bereits erledigt, wir f\u00fcgen einfach Aufrufe zu den Ruuvi-<strong>I2C<\/strong>-Bibliotheken hinzu, die wiederum das zugrunde liegende Software Development Kit (<strong>SDK)<\/strong> aufrufen. Die Arbeit wird durch die <strong>TMP117<\/strong>-Registerstruktur noch weiter vereinfacht, die Lese-\/Schreibbefehle mit fester Gr\u00f6\u00dfe hat.  <\/p>\n\n<p class=\"wp-block-paragraph\">Um die Projektstruktur sauber zu halten, erstellen wir neue Dateien:<\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi.drivers.c\/interfaces\/i2c\/ruuvi_interface_i2c_tmp117.c\nruuvi.drivers.c\/interfaces\/i2c\/ruuvi_interface_i2c_tmp117.h<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">und platzieren die Funktionalit\u00e4t dort. Du findest den Abschnitt im rechten gr\u00fcnen Kasten des Architekturdiagramms. <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * @brief I2C write function for TMP117\n *\n *\n * @param&#91;in] dev_id @ref I2C interface handle, i.e. I2C addess of TMP117\n * @param&#91;in] reg_addr TMP117 register address to write.\n * @param&#91;in] reg_val 16-bit value to be written\n * @return RUUVI_DRIVER_SUCCESS on success\n * @return RUUVI_DRIVER_ERROR_TIMEOUT if device does not respond on bus\n **\/\nruuvi_driver_status_t ruuvi_interface_i2c_tmp117_write(const uint8_t dev_id, const uint8_t reg_addr, \n                                                       const uint16_t reg_val)\n{\n  uint8_t command&#91;3];\n  command&#91;0] = reg_addr;\n  command&#91;1] = reg_val &gt;&gt; 8;\n  command&#91;2] = reg_val &amp; 0xFF\n  return ruuvi_interface_i2c_write_blocking(dev_id, command, sizeof(command), true);\n}\n\n\/**\n * @brief I2C Read function for TMP117\n *\n * Binds Ruuvi Interface I2C functions for TMP117\n *\n * @param&#91;in] dev_id @ref I2C interface handle, i.e. I2C addess of TMP117.\n * @param&#91;in] reg_addr TMP117 register address to read.\n * @param&#91;in] reg_val pointer to 16-bit data to be received.\n * @return RUUVI_DRIVER_SUCCESS on success\n * @return RUUVI_DRIVER_ERROR_TIMEOUT if device does not respond on bus\n **\/\nruuvi_driver_status_t ruuvi_interface_i2c_tmp117_read(const uint8_t dev_id, const uint8_t reg_addr,\n                                                      uint16_t* const reg_val)\n{\n  if(NULL == p_reg_data) { return RUUVI_DRIVER_ERROR_NULL; }\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n\n  uint8_t command&#91;3] = {0};\n  command&#91;0] = reg_addr;\n\n  err_code |= ruuvi_interface_i2c_write_blocking(dev_id, command, 1, false);\n  err_code |= ruuvi_interface_i2c_read_blocking(dev_id, &amp;(command&#91;1]), len);\n  reg_val = (command&#91;1] &lt;&lt; 8) + command&#91;2];\n  return err_code;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/25bf1baa0b99f91dbc78ec60cfc3766c\/raw\/1a579bce7eaeffb72bf2e7d8a5280f75d8b60886\/ruuvi_interface_i2c_tmp117.c\">Rohansicht<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Die <strong>I2C<\/strong>-Pins sind bereits in <em>ruuvi_board_kaarle.h<\/em> f\u00fcr die <strong>SHTC3<\/strong>-Unterst\u00fctzung definiert. Wir f\u00fcgen die <strong>I2C<\/strong>-Adresse von <strong>TMP117<\/strong> mit <strong>ADD0<\/strong>-Pin auf Masse zur Header-Datei hinzu: <\/p>\n\n<pre class=\"wp-block-code\"><code>#define RUUVI_BOARD_TMP117_I2C_ADDRESS             0x48<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Die Board-Definitionen befinden sich in der Mitte links im Anwendungsdiagramm.<\/p>\n\n<h2 class=\"wp-block-heading\">TMP117-Schnittstelle<\/h2>\n\n<p class=\"wp-block-paragraph\">Wir trennen die Logik f\u00fcr den Zugriff auf <strong>TMP117<\/strong> vom tats\u00e4chlichen Datenverkehr auf dem <strong>I2C<\/strong>-Bus und erstellen neue Dateien zur Steuerung des Sensors:<\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c\nruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Diese Dateien befinden sich im linken gr\u00fcnen Abschnitt des Architekturdiagramms. Wir k\u00f6nnten einen Treiber schreiben, der vollst\u00e4ndig von Ruuvi-Treibern entkoppelt ist und die <strong>I2C<\/strong>-Schnittstelle als Funktionszeiger \u00fcbernimmt, aber das w\u00fcrde aus Sicht des Ruuvi-Treibers keinen wirklichen Mehrwert bieten, also codieren wir die <strong>I2C<\/strong>-Zugriffsfunktionen einfach fest ein. <\/p>\n\n<h3 class=\"wp-block-heading\">Registerzugriff von TMP117<\/h3>\n\n<p class=\"wp-block-paragraph\">Nachdem die <strong>I2C<\/strong>-Kommunikation gekl\u00e4rt ist, schreiben wir die Registerkarte und Funktionen f\u00fcr den Zugriff auf die Register aus. Die Registerkarte selbst ist wirklich einfach mit nur 10 16-Bit-Registern. <\/p>\n\n<pre class=\"wp-block-code\"><code>ADDRESS TYPE RESET ACRONYM       REGISTER NAME\n00h     R    8000h Temp_Result   Temperature result register\n01h     R\/W  0220h Configuration Configuration register\n02h     R\/W  6000h THigh_Limit   Temperature high limit register\n03h     R\/W  8000h TLow_Limit    Temperature low limit register\n04h     R\/W  0000h EEPROM_UL     EEPROM unlock register\n05h     R\/W  xxxxh EEPROM1       EEPROM1 register\n06h     R\/W  xxxxh EEPROM2       EEPROM2 register\n07h     R\/W  0000h Temp_Offset   Temperature offset register\n08h     R\/W  xxxxh EEPROM3       EEPROM3 register\n0Fh     R    0117h Device_ID     Device ID register<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Dann implementieren wir die minimal erforderliche Konfiguration zum \u00dcberpr\u00fcfen der ID \u00fcber <strong>I2C<\/strong>, zum Durchf\u00fchren eines Soft-Resets, zum Konfigurieren des Oversampling-Verh\u00e4ltnisses, zum Konfigurieren des Konvertierungsintervalls, zum Ausl\u00f6sen von Einzel- und kontinuierlichen Messungen und zum Auslesen des Temperaturwerts.<\/p>\n\n<pre class=\"wp-block-code\"><code>#include \"ruuvi_driver_error.h\"\n#include \"ruuvi_driver_sensor.h\"\n#include \"ruuvi_interface_tmp117.h\"\n#include \"ruuvi_interface_i2c_tmp117.h\"\n\nstatic uint8_t  m_address;\nstatic uint16_t ms_per_sample; \n\nstatic ruuvi_driver_status_t tmp117_soft_reset(void)\n{\n  uint16_t reset = TMP117_MASK_RESET &amp; 0xFFFF;\n  return ruuvi_interface_i2c_tmp117_write(m_address, TMP117_REG_CONFIGURATION, reset);\n}\n\nstatic ruuvi_driver_status_t tmp117_validate_id(void)\n{\n  uint16_t id;\n  ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_DEVICE_ID, &amp;id);\n  id &amp;= TMP117_MASK_ID;\n  return (TMP117_VALUE_ID == id)? RUUVI_DRIVER_SUCCESS : RUUVI_DRIVER_ERROR_NOT_FOUND;\n}\n\nstatic ruuvi_driver_status_t tmp117_oversampling_set(const uint8_t num_os)\n{\n  uint16_t reg_val;\n  ruuvi_driver_status_t err_code;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_CONFIGURATION, &amp;reg_val);\n  reg_val &amp;= ~TMP117_MASK_OS;\n  switch(num_os)\n  {\n    case 1:\n      reg_val |= TMP117_VALUE_OS_1;\n      ms_per_sample = 16;\n      break;\n      \n    case 8:\n      reg_val |= TMP117_VALUE_OS_8;\n      ms_per_sample = 125;\n      break;\n\n    case 32:\n      reg_val |= TMP117_VALUE_OS_32;\n      ms_per_sample = 500;\n      break;\n\n    case 64:\n      reg_val |= TMP117_VALUE_OS_64;\n      ms_per_sample = 1000;\n      break;\n\n    default:\n      return RUUVI_DRIVER_ERROR_INVALID_PARAM;\n  }\n  err_code |= ruuvi_interface_i2c_tmp117_write(m_address, TMP117_REG_CONFIGURATION, reg_val);\n  return err_code;\n}\n\nstatic ruuvi_driver_status_t tmp117_sleep(void)\n{\n  uint16_t reg_val;\n  ruuvi_driver_status_t err_code;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_CONFIGURATION, &amp;reg_val);\n  reg_val &amp;= ~TMP117_MASK_MODE;\n  reg_val |= TMP117_VALUE_MODE_SLEEP;\n  err_code |= ruuvi_interface_i2c_tmp117_write(m_address, TMP117_REG_CONFIGURATION, reg_val);\n  return  err_code;\n}\n\nstatic ruuvi_driver_status_t tmp117_sample(void)\n{\n  uint16_t reg_val;\n  ruuvi_driver_status_t err_code;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_CONFIGURATION, &amp;reg_val);\n  reg_val &amp;= ~TMP117_MASK_MODE;\n  reg_val |= TMP117_VALUE_MODE_SINGLE;\n  err_code |= ruuvi_interface_i2c_tmp117_write(m_address, TMP117_REG_CONFIGURATION, reg_val);\n  return  err_code;\n}\n\nstatic ruuvi_driver_status_t tmp117_continuous(void)\n{\n  uint16_t reg_val;\n  ruuvi_driver_status_t err_code;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_CONFIGURATION, &amp;reg_val);\n  reg_val &amp;= ~TMP117_MASK_MODE;\n  reg_val |= TMP117_VALUE_MODE_CONT;\n  err_code |= ruuvi_interface_i2c_tmp117_write(m_address, TMP117_REG_CONFIGURATION, reg_val);\n  return  err_code;\n}\n\nstatic float tmp117_read(void)\n{\n  uint16_t reg_val;\n  ruuvi_driver_status_t err_code;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_TEMP_RESULT, &amp;reg_val);\n  int16_t temperature = (reg_val &gt; 32767)? reg_val - 65535 : reg_val;\n  float temperature = (0.0078125 * temperature);\n  if(TMP117_VALUE_TEMP_NA == reg_val || RUUVI_DRIVER_SUCCESS != err_code) { temperature = NAN; }\n  return temperature;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/cd29e56fd5cb540eb38ab42e15559b8c\/raw\/e97b62969626a6c6c50427506f9f197aa192a453\/ruuvi_interface_tmp117_static.c\">Rohansicht<\/a><\/p>\n\n<h3 class=\"wp-block-heading\">High-Level-Zugriff auf TMP117<\/h3>\n\n<p class=\"wp-block-paragraph\">Die Ruuvi-Firmware erwartet, dass die Treiber eine einheitliche Schnittstelle zu den Treibern bereitstellen. Auf diese Weise k\u00f6nnen wir das Backend, das Daten bereitstellt, austauschen, ohne die Anwendungslogik \u00fcberarbeiten zu m\u00fcssen. Lass uns die erforderlichen Funktionen \u00fcber Low-Level-Zugriffsfunktionen implementieren.  <\/p>\n\n<h4 class=\"wp-block-heading\"><strong>Initialisierung<\/strong><\/h4>\n\n<p class=\"wp-block-paragraph\">Die Initialisierung bereitet den Sensor f\u00fcr die Verwendung vor, f\u00fchrt alle Selbsttests durch und versetzt den Sensor in den niedrigstm\u00f6glichen Stromzustand. Die Initialisierung sperrt den Sensor auch f\u00fcr andere Benutzer, bis er deinitialisiert wurde. <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * @brief Initialize and uninitialize sensor.\n * Init and uninit will setup sensor with function pointers.\n * The sensor wil be initialized to lowest power state possible.\n *\n * @param&#91;in,out] p_sensor pointer to sensor structure\n * @param&#91;in] bus bus to use, i.r. I2C or SPI\n * @param&#91;in] handle for the sensor, for example I2C address or SPI chip select pin\n * @return @c RUUVI_DRIVER_SUCCESS on success\n * @return @c RUUVI_DRIVER_ERROR_NULL if p_sensor is NULL\n * @return @c RUUVI_DRIVER_ERROR_NOT_FOUND if there is no response from sensor or if ID of\n *            a sensor read over bus does not match expected value\n * @return @c RUUVI_DRIVER_ERROR_SELFTEST if sensor is found but it does not pass selftest\n * @return @c RUUVI_DRIVER_ERROR_INVALID_STATE if trying to initialize sensor which \n *            already has been initialized.\n **\/\ntypedef ruuvi_driver_status_t (*ruuvi_driver_sensor_init_fp)(ruuvi_driver_sensor_t* const\n    p_sensor, const ruuvi_driver_bus_t bus, const uint8_t handle);<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/5e8b01339a995af67de7fe90b8db16d4\/raw\/a781c73532d2b7847db5e6115b99276d5c08efe9\/ruuvi_sensor_init.c\">Rohansicht<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Die Implementierung ist unkompliziert. Wir \u00fcberpr\u00fcfen die Eingaben, lesen die ID von <strong>TMP117<\/strong> \u00fcber <strong>I2C<\/strong> und konfigurieren dann die Funktionszeiger, den Sensornamen, die bereitgestellten Daten und gehen in den Ruhezustand. Die gespeicherte <strong>I2C<\/strong>-Adresse fungiert als Sperre f\u00fcr den Sensor.  <\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi_driver_status_t ruuvi_interface_tmp117_init(ruuvi_driver_sensor_t*\n    environmental_sensor, ruuvi_driver_bus_t bus, uint8_t handle)\n{\n  if(NULL == environmental_sensor) { return RUUVI_DRIVER_ERROR_NULL; }\n  if(m_address) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n\n  ruuvi_driver_sensor_initialize(environmental_sensor);\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  m_address = handle;\n  size_t retries = 0;\n\n  switch(bus)\n  {\n    case RUUVI_DRIVER_BUS_I2C:\n      do{\n      err_code |= tmp117_validate_id();\n      retries++;\n      }while(RUUVI_DRIVER_ERROR_TIMEOUT == err_code &amp;&amp; retries &lt; 5);\n      break;\n\n    default:\n      return  RUUVI_DRIVER_ERROR_INVALID_PARAM;\n  }\n  if(RUUVI_DRIVER_SUCCESS != err_code) { err_code = RUUVI_DRIVER_ERROR_NOT_FOUND; }\n\n  if(RUUVI_DRIVER_SUCCESS == err_code)\n  {\n    environmental_sensor-&gt;init              = ruuvi_interface_tmp117_init;\n    environmental_sensor-&gt;uninit            = ruuvi_interface_tmp117_uninit;\n    environmental_sensor-&gt;samplerate_set    = ruuvi_interface_tmp117_samplerate_set;\n    environmental_sensor-&gt;samplerate_get    = ruuvi_interface_tmp117_samplerate_get;\n    environmental_sensor-&gt;resolution_set    = ruuvi_interface_tmp117_resolution_set;\n    environmental_sensor-&gt;resolution_get    = ruuvi_interface_tmp117_resolution_get;\n    environmental_sensor-&gt;scale_set         = ruuvi_interface_tmp117_scale_set;\n    environmental_sensor-&gt;scale_get         = ruuvi_interface_tmp117_scale_get;\n    environmental_sensor-&gt;dsp_set           = ruuvi_interface_tmp117_dsp_set;\n    environmental_sensor-&gt;dsp_get           = ruuvi_interface_tmp117_dsp_get;\n    environmental_sensor-&gt;mode_set          = ruuvi_interface_tmp117_mode_set;\n    environmental_sensor-&gt;mode_get          = ruuvi_interface_tmp117_mode_get;\n    environmental_sensor-&gt;data_get          = ruuvi_interface_tmp117_data_get;\n    environmental_sensor-&gt;configuration_set = ruuvi_driver_sensor_configuration_set;\n    environmental_sensor-&gt;configuration_get = ruuvi_driver_sensor_configuration_get;\n    environmental_sensor-&gt;name              = m_sensor_name;\n    environmental_sensor-&gt;provides.datas.temperature_c = 1;\n    m_timestamp = RUUVI_DRIVER_UINT64_INVALID;\n    m_temperature = NAN;\n    tmp117_sleep();\n  }\n\n  return err_code;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_uninit(ruuvi_driver_sensor_t* sensor,\n    ruuvi_driver_bus_t bus, uint8_t handle)\n{\n  if(NULL == sensor) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  tmp117_sleep();\n\n  ruuvi_driver_sensor_uninitialize(sensor);\n  m_timestamp = RUUVI_DRIVER_UINT64_INVALID;\n  m_temperature = NAN;\n  m_address = 0;\n  return err_code;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/2d2a10c158c405a2726b24497cf95d46\/raw\/6407168ebe2bdb2835674c193e9b8f5a75236bc4\/ruuvi_interface_tmp117_init.c\">Rohansicht<\/a><\/p>\n\n<h3 class=\"wp-block-heading\">Konfiguration<\/h3>\n\n<p class=\"wp-block-paragraph\"><strong>TMP117<\/strong> hat eine feste Aufl\u00f6sung und Skalierung. Die Abtastrate kann \u00fcber die Konvertierungszykluszeit im kontinuierlichen Modus konfiguriert werden. Die einzige digitale Signalverarbeitung (<strong>DSP<\/strong>), die von <strong>TMP117<\/strong> unterst\u00fctzt wird, ist Oversampling.  <\/p>\n\n<p class=\"wp-block-paragraph\">Wir geben eine Warnung zur\u00fcck, wenn der Benutzer versucht, das Oversampling auf ein h\u00f6heres Verh\u00e4ltnis einzustellen, als von der aktuellen Abtastrate unterst\u00fctzt wird, oder umgekehrt. Zus\u00e4tzlich unterst\u00fctzt das Standard-Sensorkonfigurationsformat nur Abtastraten im Bereich von 1 \u2026 200 <em>Hz<\/em>, w\u00e4hrend <strong>TMP117<\/strong> Raten von 1\/4, 1\/8 und 1\/16 <em>Hz<\/em> unterst\u00fctzt. Wir implementieren diese Raten als benutzerdefinierte Werte f\u00fcr den Sensor.  <\/p>\n\n<p class=\"wp-block-paragraph\">Die Konfigurationsfunktionssignaturen sind in <em>ruuvi_driver_sensor.h<\/em> definiert. Lass uns sie mit den obigen Low-Level-Funktionen implementieren.<\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n *  @brief Setup a parameter of a sensor.\n *  The function will modify the pointed data to the actual value which was written\n *\n *  @param&#91;in,out] parameter value to write to sensor configuration. Actual value written to sensor as output\n *  @return RUUVI_DRIVER_SUCCESS on success\n *  @return RUUVI_DRIVER_ERROR_NULL if parameter is NULL\n *  @return RUUVI_DRIVER_ERROR_NOT_SUPPORTED if sensor cannot support given parameter\n *  @return RUUVI_DRIVER_ERROR_NOT_IMPLEMENTED if the sensor could support parameter, but it's not implemented in fw.\n **\/\ntypedef ruuvi_driver_status_t (*ruuvi_driver_sensor_setup_fp)(uint8_t* parameter);\n\n\/**\n * @brief Configure sensor digital signal processing.\n * Takes DSP function and a DSP parameter as input, configured value or error code as output.\n * Modifies input parameters to actual values written on the sensor.\n * DSP functions are run on the sensor HW, not in the platform FW.\n *\n * @param&#91;in,out] dsp_function. DSP function to run on sensor. Can be a combination of several functions.\n * @param&#91;in,out] dsp_parameter. Parameter to DSP function(s)\n * @return RUUVI_DRIVER_SUCCESS on success\n * @return RUUVI_DRIVER_ERROR_NULL if either parameter is NULL\n * @return RUUVI_DRIVER_ERROR_NOT_SUPPORTED if sensor doesn't support given DSP\n * @return RUUVI_DRIVER_ERROR_NOT_IMPLEMENTED if sensor supports given DSP, but\n *         driver does not implement it\n * @return RUUVI_DRIVER_ERROR_INVALID_PARAM if parameter is invalid for any reason.\n **\/\ntypedef ruuvi_driver_status_t (*ruuvi_driver_sensor_dsp_fp)(uint8_t* dsp_function,\n    uint8_t* dsp_parameter);<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/edb483740213166d6d0ff69aa16d7961\/raw\/bfebcc70c71d3537e9458d545a78a0d3161a2072\/ruuvi_interface_config_functions.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Signatur f\u00fcr Konfigurationsfunktion<\/em><\/p>\n\n<h4 class=\"wp-block-heading\"><strong>Abtastrate<\/strong><\/h4>\n\n<p class=\"wp-block-paragraph\">Die vom Benutzer angegebene Abtastrate wird als <em>mindestens so viel<\/em> verstanden. Daher runden wir die vom Benutzer angeforderte Abtastrate auf. Wir betrachten auch 1 <em>Hz<\/em> als Standardoption.<\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi_driver_status_t ruuvi_interface_tmp117_samplerate_set(uint8_t* samplerate)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n\n  if(RUUVI_DRIVER_SENSOR_CFG_DEFAULT == *samplerate ||\n     1 &gt;= *samplerate) \n  { \n    *samplerate = 1;\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_1000_MS);\n  }\n  else if(2 &gt;= *samplerate) \n  { \n    *samplerate = 2;\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_500_MS);\n  }\n  else if(4 &gt;= *samplerate) \n  { \n    *samplerate = 4;\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_250_MS);\n  }\n  else if(8 &gt;= *samplerate) \n  { \n    *samplerate = 8;\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_125_MS);\n  }\n  else if(64 &gt;= *samplerate) \n  { \n    *samplerate = 64;\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_16_MS);\n  }\n  else if (RUUVI_DRIVER_SENSOR_CFG_CUSTOM_1 == *samplerate)\n  {\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_4000_MS);\n  }\n  else if (RUUVI_DRIVER_SENSOR_CFG_CUSTOM_2 == *samplerate)\n  {\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_8000_MS);\n  }\n  else if (RUUVI_DRIVER_SENSOR_CFG_CUSTOM_3 == *samplerate)\n  {\n    err_code |= tmp117_samplerate_set(TMP117_VALUE_CC_16000_MS);\n  }\n  return  err_code;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_samplerate_get(uint8_t* samplerate)\n{\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  uint16_t reg_val;\n  err_code = ruuvi_interface_i2c_tmp117_read(m_address, TMP117_REG_CONFIGURATION, &amp;reg_val);\n  reg_val &amp;= TMP117_MASK_CC;\n  switch(reg_val)\n  {\n    case TMP117_VALUE_CC_16_MS:\n      *samplerate = 64;\n      break;\n\n    case TMP117_VALUE_CC_125_MS:\n      *samplerate = 8;\n      break;\n\n    case TMP117_VALUE_CC_250_MS:\n      *samplerate = 4;\n      break;\n\n    case TMP117_VALUE_CC_500_MS:\n      *samplerate = 2;\n      break;\n\n    case TMP117_VALUE_CC_1000_MS:\n      *samplerate = 1;\n      break;\n\n    case TMP117_VALUE_CC_4000_MS:\n      *samplerate = RUUVI_DRIVER_SENSOR_CFG_CUSTOM_1;\n      break;\n\n    case TMP117_VALUE_CC_8000_MS:\n      *samplerate = RUUVI_DRIVER_SENSOR_CFG_CUSTOM_2;\n      break;\n\n    case TMP117_VALUE_CC_16000_MS:\n      *samplerate = RUUVI_DRIVER_SENSOR_CFG_CUSTOM_3;\n      break;\n\n    default:\n     return RUUVI_DRIVER_ERROR_INTERNAL;\n  }\n  return err_code;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/09c5ceec2b0603c1dbd550211f86479c\/raw\/1fac5838f8be330d05c4989d2c0ef5b05fb89aa9\/ruuvi_interface_tmp117_samplerate.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Das Konfigurieren der Abtastrate endet als einfache, aber lange Switch-Case-Anweisung<\/em><\/p>\n\n<h4 class=\"wp-block-heading\"><strong>Aufl\u00f6sung, Skalierung<\/strong><\/h4>\n\n<p class=\"wp-block-paragraph\">Da Aufl\u00f6sung und Skalierung bei <strong>TMP117<\/strong> fest vorgegeben sind, m\u00fcssen wir nur Werte f\u00fcr Minimum, Maximum, Standard und \u201ekeine \u00c4nderung\u201c zulassen. Alles andere kann den Fehler \u201enicht unterst\u00fctzt\u201c zur\u00fcckgeben. <\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi_driver_status_t ruuvi_interface_tmp117_resolution_set(uint8_t* resolution)\n{\n  if(NULL == resolution) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  uint8_t original = *resolution;\n  *resolution = RUUVI_DRIVER_SENSOR_CFG_DEFAULT;\n  RETURN_SUCCESS_ON_VALID(original);\n  return RUUVI_DRIVER_ERROR_NOT_SUPPORTED;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_resolution_get(uint8_t* resolution)\n{\n  if(NULL == resolution) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  *resolution = RUUVI_DRIVER_SENSOR_CFG_DEFAULT;\n  return RUUVI_DRIVER_SUCCESS;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_scale_set(uint8_t* scale)\n{\n  if(NULL == scale) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  uint8_t original = *scale;\n  *scale = RUUVI_DRIVER_SENSOR_CFG_DEFAULT;\n  RETURN_SUCCESS_ON_VALID(original);\n  return RUUVI_DRIVER_ERROR_NOT_SUPPORTED;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_scale_get(uint8_t* scale)\n{\n  if(NULL == scale) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  *scale = RUUVI_DRIVER_SENSOR_CFG_DEFAULT;\n  return RUUVI_DRIVER_SUCCESS;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/c01b5cca06875b80d6744f9105dac89e\/raw\/f7095224db44a5ab199f4ee5fd44b9793065e4ec\/ruuvi_interface_tmp117_scale_resolution.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Einfach genug Boilerplate<\/em><\/p>\n\n<h4 class=\"wp-block-heading\"><strong>Digitale Signalverarbeitung<\/strong><\/h4>\n\n<p class=\"wp-block-paragraph\"><strong>TMP117<\/strong> unterst\u00fctzt Oversampling des Sensors, d. h. das Nehmen mehrerer Proben und deren Mittelung, um Rauschen zu reduzieren, aber den Stromverbrauch zu erh\u00f6hen. Die <strong>DSP<\/strong>-Konfigurationssignatur unterscheidet sich von den anderen Konfigurationsfunktionen, da sie sowohl den Typ von <strong>DSP<\/strong> als auch einen Parameter zur Konfiguration der Aggressivit\u00e4t von <strong>DSP<\/strong> enth\u00e4lt. <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * @brief Configure sensor digital signal processing.\n * Takes DSP function and a DSP parameter as input, configured value or error code as output.\n * Modifies input parameters to actual values written on the sensor.\n * DSP functions are run on the sensor HW, not in the platform FW.\n *\n * @param&#91;in,out] dsp_function. DSP function to run on sensor. Can be a combination of several functions.\n * @param&#91;in,out] dsp_parameter. Parameter to DSP function(s)\n * @return RUUVI_DRIVER_SUCCESS on success\n * @return RUUVI_DRIVER_ERROR_NULL if either parameter is NULL\n * @return RUUVI_DRIVER_ERROR_NOT_SUPPORTED if sensor doesn't support given DSP\n * @return RUUVI_DRIVER_ERROR_NOT_IMPLEMENTED if sensor supports given DSP, but\n *         driver does not implement it\n * @return RUUVI_DRIVER_ERROR_INVALID_PARAM if parameter is invalid for any reason.\n **\/\ntypedef ruuvi_driver_status_t (*ruuvi_driver_sensor_dsp_fp)(uint8_t* dsp_function,\n    uint8_t* dsp_parameter);<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/6a2a80bea17c203169ae3cc393403068\/raw\/2249b9e8b79f603af9ae061d1fd6dc8273bd41cb\/ruuvi_driver_dsp.h\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>DSP-Konfigurationssignatur<\/em><\/p>\n\n<p class=\"wp-block-paragraph\">Jetzt sind die erforderlichen Konfigurationsfunktionen vorhanden. Unsere Sensorschnittstelle w\u00fcrde das Setzen des Interrupts unterst\u00fctzen, aber wir lassen die Implementierung vorerst weg. <\/p>\n\n<h2 class=\"wp-block-heading\"><strong>Abtastung: Ruhezustand, Einzel, Kontinuierlich<\/strong><\/h2>\n\n<p class=\"wp-block-paragraph\">Wie bei allen batteriebetriebenen Ger\u00e4ten ist Energie die wertvollste Ressource im System und muss so weit wie m\u00f6glich geschont werden. Der niedrigste Stromzustand des Sensors ist der Ruhezustand. Eine Einzelmessung weckt den Sensor zum Nehmen einer Probe auf, wartet, bis die Probe abgeschlossen ist, und versetzt den Sensor dann wieder in den Ruhezustand. Der kontinuierliche Modus l\u00e4sst den Sensor in einem frei laufenden Modus, der die Daten kontinuierlich abtastet.   <\/p>\n\n<p class=\"wp-block-paragraph\">Der kontinuierliche Modus ist n\u00fctzlich, wenn Proben schnell genommen werden, wenn Interrupts basierend auf Sensorwerten verwendet werden oder wenn der Sensor interne digitale Signalverarbeitung ausf\u00fchrt.<\/p>\n\n<p class=\"wp-block-paragraph\">Im Allgemeinen ist der Einzelmodus am besten, wenn Proben mit einer Frequenz unter 1 <em>Hz<\/em> genommen werden, aber da <strong>TMP117<\/strong> kontinuierliche Abtastung bis zu 1\/16 <em>Hz<\/em> unterst\u00fctzt, k\u00f6nnen wir praktisch immer den kontinuierlichen Modus verwenden. Lass uns die High-Level-Aufrufe zum Einstellen des Modus implementieren. <\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi_driver_status_t ruuvi_interface_tmp117_mode_set(uint8_t* mode)\n{\n  if(NULL == mode) { return RUUVI_DRIVER_ERROR_NULL; }\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  switch(*mode)\n  {\n    case RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS:\n      err_code |= tmp117_continuous();\n      m_continuous = true;\n      break;\n\n    case RUUVI_DRIVER_SENSOR_CFG_SINGLE:\n      if(m_continuous) { return RUUVI_DRIVER_ERROR_INVALID_STATE; }\n      err_code |= tmp117_sample();\n      ruuvi_interface_delay_ms(ms_per_sample);\n      break;\n\n    case RUUVI_DRIVER_SENSOR_CFG_SLEEP:\n      err_code |= tmp117_sleep();\n      m_continuous = false;\n      break;\n\n    default:\n      err_code |= RUUVI_DRIVER_ERROR_INVALID_PARAM;\n  }\n  return err_code;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_mode_get(uint8_t* mode)\n{\n  if(NULL == mode) { return RUUVI_DRIVER_ERROR_NULL; }\n  *mode = m_continuous ? RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS : RUUVI_DRIVER_SENSOR_CFG_SLEEP;\n  return RUUVI_DRIVER_SUCCESS;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/af2e1e095d41f959594b8cbd23489cf3\/raw\/9425c650be6a2675fa9c7bc294061338edefa806\/ruuvi_interface_tmp117_mode.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Setzen und Abrufen des aktuellen Modus<\/em><\/p>\n\n<h2 class=\"wp-block-heading\">Daten auslesen<\/h2>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes kommen wir zum eigentlichen Kern unseres Treibers: dem Auslesen von Daten. Die Ruuvi-Sensordatenstruktur hat sich in FW-Version 3.26.0 ge\u00e4ndert. Fr\u00fchere Versionen zwangen jeden Sensor, seine Daten in 3 Floats einzupassen, w\u00e4hrend das neue Datenformat bis zu 32 Felder pro Sensor unterst\u00fctzt. Wir lesen den Sensorwert aus und f\u00fcllen das Temperaturdatenfeld.  <\/p>\n\n<pre class=\"wp-block-code\"><code>\/**\n * @brief Read latest data from sensor registers\n * Return latest data from sensor. Does not take a new sample, calling this function twice\n * in a row returns same data. Configure sensor in a single-shot mode to take a new sample\n * or leave sensor in a continuous mode to get updated data.\n *\n * @param &#91;out] p_data Pointer to sensor data @ref ruuvi_driver_sensor_data_t .\n * @return RUUVI_DRIVER_SUCCESS on success\n * @return RUUVI_DRIVER_ERROR_NULL if p_data is @c NULL.\n *\n * @warning if sensor data is not valid for any reason, data is populated with \n *          @c RUUVI_DRIVER_FLOAT_INVALID.\n *\/\ntypedef ruuvi_driver_status_t (*ruuvi_driver_sensor_data_fp)(ruuvi_driver_sensor_data_t* const p_data);<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/004bfc358e919966933101572e52ecfd\/raw\/ce85ba44d4706ba12cc64ef67d85b52f9045ae6a\/ruuvi_driver_dsp.h\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Sensordaten-Get-Signatur<\/em><\/p>\n\n<pre class=\"wp-block-code\"><code>ruuvi_driver_status_t ruuvi_interface_tmp117_mode_get(uint8_t* mode)\n{\n  if(NULL == mode) { return RUUVI_DRIVER_ERROR_NULL; }\n  *mode = m_continuous ? RUUVI_DRIVER_SENSOR_CFG_CONTINUOUS : RUUVI_DRIVER_SENSOR_CFG_SLEEP;\n  return RUUVI_DRIVER_SUCCESS;\n}\n\nruuvi_driver_status_t ruuvi_interface_tmp117_data_get(ruuvi_driver_sensor_data_t* const  data)\n{\n  if(NULL == data) { return RUUVI_DRIVER_ERROR_NULL; }\n\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_SUCCESS;\n  if(m_continuous) \n  { \n    m_temperature = tmp117_read();\n    m_timestamp = ruuvi_driver_sensor_timestamp_get();\n  }\n\n  if(RUUVI_DRIVER_SUCCESS == err_code &amp;&amp; RUUVI_DRIVER_UINT64_INVALID != m_timestamp)\n  {\n    ruuvi_driver_sensor_data_fields_t env_fields = {.bitfield = 0};\n    env_fields.datas.temperature_c = 1;\n    ruuvi_driver_sensor_data_set(data,\n                                 env_fields,\n                                 m_temperature);\n    data-&gt;timestamp_ms = m_timestamp;\n  }\n\n  return err_code;\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/2c130be5a0d9eac4ccd84273352471c6\/raw\/0641f6b814e510e4e26a3ebfd4b41df09d3810f3\/ruuvi_interface_tmp117_data.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Daten-Getter-Implementierung<\/em><\/p>\n\n<h2 class=\"wp-block-heading\"><strong>Testen<\/strong><\/h2>\n\n<p class=\"wp-block-paragraph\">Da dies ziemlich viel Code war, sind in der Arbeit, die wir implementiert haben, sicher Fehler enthalten. Deshalb haben wir die <em>Unit-Tests<\/em> f\u00fcr die Sensorschnittstelle. Wir f\u00fchren dieselbe Testbatterie f\u00fcr jede Implementierung von Sensorschnittstellen durch, um sicherzustellen, dass ihr Verhalten konsistent ist. Auf diese Weise k\u00f6nnen wir verschiedene Sensoren auf verschiedenen Boards verwenden, ohne uns um die Details der zugrunde liegenden Implementierung sorgen zu m\u00fcssen.   <\/p>\n\n<pre class=\"wp-block-code\"><code>  #if RUUVI_BOARD_ENVIRONMENTAL_TMP117_PRESENT\n    bus = RUUVI_DRIVER_BUS_I2C;\n    handle = RUUVI_BOARD_TMP117_I2C_ADDRESS;\n    err_code = test_run(ruuvi_interface_tmp117_init, bus, handle);\n    RUUVI_DRIVER_ERROR_CHECK(err_code, RUUVI_DRIVER_ERROR_SELFTEST);\n  #endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/9107d21e8071b1b9c8736cf621785abf\/raw\/955bca44f5d6137ab6f0260676bc1aa71dff8337\/test_tmp117.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Wir haben den Code zum Ausf\u00fchren der Testbatterie zu tests\/test_environmental.c hinzugef\u00fcgt. Der Testabschnitt befindet sich in der oberen rechten Ecke des Anwendungsdiagramms. <\/em><\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"964\" height=\"278\" src=\"https:\/\/ruuvi.com\/i\/u\/debug-terminal-detection.png\" alt=\"Debug-Terminal hat 7 Fehler erkannt\" class=\"wp-image-4023\" srcset=\"https:\/\/ruuvi.com\/i\/u\/debug-terminal-detection.png 964w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-detection-450x130.png 450w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-detection-768x221.png 768w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-detection-600x173.png 600w\" sizes=\"auto, (max-width: 964px) 100vw, 964px\" \/><figcaption>Unsere Unit-Tests haben 7 Fehler im obigen Code erkannt. Als N\u00e4chstes graben wir in test_sensor.c an den angegebenen Zeilen und beheben sie. <\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Der K\u00fcrze halber gehen wir nur den ersten Fehler im Detail durch.<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"348\" src=\"https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode-1024x348.png\" alt=\"Fehler liegt im erneuten Eintritt in den Ruhezustand nach dem Nehmen einer Einzelprobe\" class=\"wp-image-4024\" srcset=\"https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode-1024x348.png 1024w, https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode-450x153.png 450w, https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode-768x261.png 768w, https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode-600x204.png 600w, https:\/\/ruuvi.com\/i\/u\/bug-in-re-entering-sleep-mode.png 1406w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Der Fehler liegt im erneuten Eintritt in den Ruhezustand nach dem Nehmen einer Einzelprobe<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"863\" src=\"https:\/\/ruuvi.com\/i\/u\/added-line-1024x863.png\" alt=\"F&#xFC;ge eine Codezeile hinzu, um den Modus als schlafend zu markieren, nachdem die Einzelprobe genommen wurde\" class=\"wp-image-4025\" srcset=\"https:\/\/ruuvi.com\/i\/u\/added-line-1024x863.png 1024w, https:\/\/ruuvi.com\/i\/u\/added-line-450x379.png 450w, https:\/\/ruuvi.com\/i\/u\/added-line-768x647.png 768w, https:\/\/ruuvi.com\/i\/u\/added-line-600x506.png 600w, https:\/\/ruuvi.com\/i\/u\/added-line.png 1096w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Wir f\u00fcgen eine Zeile hinzu, um den Modus als schlafend zu markieren, nachdem die Einzelprobe genommen wurde<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Der Fehler in Zeile <strong>test_sensor.c:433<\/strong> hing ebenfalls mit dem Nehmen einer Einzelprobe zusammen, der Zeitstempel der Probe wurde nicht gesetzt.<\/p>\n\n<p class=\"wp-block-paragraph\">Schlie\u00dflich hing der Fehler in Zeile <strong>test_sensor.c:490<\/strong> auch mit der Konfiguration des Sensors zum Nehmen einer Einzelprobe zusammen. Der Sensor muss das Nehmen einer Einzelprobe ablehnen, w\u00e4hrend er kontinuierlich ist, und den Modus nach dem Ablehnen des neuen Modus als kontinuierlich markieren. Der Code lehnte die \u00c4nderung nur ab, ohne den tats\u00e4chlichen Zustand auf den Modusparameter zu aktualisieren.  <\/p>\n\n<p class=\"wp-block-paragraph\">Die restlichen Fehler wurden nicht von der Unit-Test-Suite gekennzeichnet. Nach dem Hinzuf\u00fcgen einiger weiterer \u00dcberpr\u00fcfungen zu den Tests wurden einige Fehler bei der Eingabe\u00fcberpr\u00fcfung der Funktionen gefunden. Haupts\u00e4chlich betrafen die Fehler das Zulassen der Konfiguration des Sensors, w\u00e4hrend er sich nicht im Ruhezustand befand, und einige Fehler hingen mit der Konfiguration der Abtastrate zusammen. <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"870\" height=\"150\" src=\"https:\/\/ruuvi.com\/i\/u\/debug-terminal-all-tests-pass.png\" alt=\"Debug-Terminal. Alle Tests bestanden, wir k&#xF6;nnen loslegen. \" class=\"wp-image-4026\" srcset=\"https:\/\/ruuvi.com\/i\/u\/debug-terminal-all-tests-pass.png 870w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-all-tests-pass-450x78.png 450w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-all-tests-pass-768x132.png 768w, https:\/\/ruuvi.com\/i\/u\/debug-terminal-all-tests-pass-600x103.png 600w\" sizes=\"auto, (max-width: 870px) 100vw, 870px\" \/><figcaption>Alle Tests bestanden, wir k\u00f6nnen loslegen.<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Sensor zur Anwendung hinzuf\u00fcgen<\/h2>\n\n<h3 class=\"wp-block-heading\">Umgebungsaufgabe<\/h3>\n\n<p class=\"wp-block-paragraph\">Jetzt, da wir den Sensor einsatzbereit haben, m\u00fcssen wir ihn zur Anwendung hinzuf\u00fcgen. Der logische Ort f\u00fcr den Sensor ist in <em>task_environmental.c<\/em>. Die Aufgaben befinden sich in der oberen linken Ecke des Anwendungsdiagramms.  <\/p>\n\n<p class=\"wp-block-paragraph\">Wir f\u00fcgen den Sensor zur Aufz\u00e4hlung m\u00f6glicher Umgebungssensoren hinzu, sodass der Platz f\u00fcr den Sensor nur auf Boards reserviert wird, die tats\u00e4chlich den <strong>TMP117<\/strong> haben k\u00f6nnten.<\/p>\n\n<p class=\"wp-block-paragraph\">Die Initialisierungsfunktion \u00fcberpr\u00fcft, ob eine Konfiguration f\u00fcr den Sensor im Flash gespeichert ist, und wenn nicht, verwendet sie die in der Anwendungskonfiguration definierten Standardwerte.<\/p>\n\n<pre class=\"wp-block-code\"><code>\/\/ Do not compile space for unused sensor drivers.\n\/\/ Define enum in order of default preference of sensor being used.\n\/\/ Default sensor can be overridden by calling a backend_set function.\nenum{\n#if APPLICATION_ENVIRONMENTAL_TMP117_ENABLED\n  ENV_TMP117_INDEX,\n#endif\n#if APPLICATION_ENVIRONMENTAL_SHTCX_ENABLED\n  ENV_SHTCX_INDEX,\n#endif\n#if APPLICATION_ENVIRONMENTAL_BME280_ENABLED\n  ENV_BME280_INDEX,\n#endif\n#if APPLICATION_ENVIRONMENTAL_NTC_ENABLED\n  ENV_LIS2DH12_INDEX,\n#endif\n#if APPLICATION_ENVIRONMENTAL_MCU_ENABLED\n  ENV_MCU_INDEX,\n#endif\n#if APPLICATION_ENVIRONMENTAL_LIS2DH12_ENABLED\n  ENV_LIS2DH12_INDEX,\n#endif\n  ENV_SENSOR_COUNT\n};\n\/** @brief Try to initialize TMP117 as environmental sensor \n *\n * Looks up appropriate pin definitions from ruuvi_boards.h\n * Tries to load driver configuration from flash. If flash configuration is not available,\n * uses application defaults from application_config.h.\n *\n * @return RUUVI_DRIVER_SUCCESS if TMP117 environmental is not enabled at compile time or if sensor is initialized.\n * @return RUUVI_DRIVER_ERROR_NOT_FOUND if TMP117 environmental does not reply on bus but it's expected to be available\n * @return RUUVI_DRIVER_ERROR_INVALID_STATE if some other user has already initialized the driver.\n *\/\nstatic ruuvi_driver_status_t initialize_tmp117(void)\n{\n  #if APPLICATION_ENVIRONMENTAL_TMP117_ENABLED\n  \/\/ Assume \"Not found\", gets set to \"Success\" if a usable sensor is present\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_ERROR_NOT_FOUND;\n  ruuvi_driver_bus_t bus = RUUVI_DRIVER_BUS_I2C;\n  uint8_t handle = RUUVI_BOARD_TMP117_I2C_ADDRESS;\n    \/\/ Initialize sensor.\n  err_code = ruuvi_interface_tmp117_init(&amp;(m_environmental_sensors&#91;ENV_TMP117_INDEX]),\n                                            bus, handle);\n  \/\/ return if failed.\n  if(RUUVI_DRIVER_SUCCESS != err_code) { return err_code; }\n  \/\/ Wait for flash operation to finish\n  while(task_flash_busy());\n  ruuvi_driver_sensor_configuration_t config;\n  err_code = task_flash_load(APPLICATION_FLASH_ENVIRONMENTAL_FILE,\n                             APPLICATION_FLASH_ENVIRONMENTAL_TMP117_RECORD,\n                             &amp;config,\n                             sizeof(config));\n  \/\/ If there is no stored configuration, use defaults.\n  if(RUUVI_DRIVER_SUCCESS != err_code)\n  {\n    LOG(\"LIS2DH12 temp config not found on flash, using defaults\\r\\n\");\n    config.dsp_function  = APPLICATION_ENVIRONMENTAL_TMP117_DSP_FUNC;\n    config.dsp_parameter = APPLICATION_ENVIRONMENTAL_TMP117_DSP_PARAM;\n    config.mode          = APPLICATION_ENVIRONMENTAL_TMP117_MODE;\n    config.resolution    = APPLICATION_ENVIRONMENTAL_TMP117_RESOLUTION;\n    config.samplerate    = APPLICATION_ENVIRONMENTAL_TMP117_SAMPLERATE;\n    config.scale         = APPLICATION_ENVIRONMENTAL_TMP117_SCALE;\n    \/\/ Store defaults to flash\n    err_code = task_flash_store(APPLICATION_FLASH_ENVIRONMENTAL_FILE,\n                                APPLICATION_FLASH_ENVIRONMENTAL_TMP117_RECORD,\n                                &amp;config,\n                                sizeof(config));\n  }\n  \/\/ Check flash operation status, allow not supported in case we're on 811\n  RUUVI_DRIVER_ERROR_CHECK(err_code, RUUVI_DRIVER_ERROR_NOT_SUPPORTED);\n  \/\/ Wait for flash operation to finish\n  while(task_flash_busy());\n  \/\/ Configure sensor\n  return task_sensor_configure(&amp;(m_environmental_sensors&#91;ENV_TMP117_INDEX]), &amp;config, \"\");\n  #else\n  return RUUVI_DRIVER_SUCCESS;\n  #endif\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/ecb966ec577062e3b230e94d733abc7e\/raw\/f1896308e29c5847cc90521c05f01cf0bb26f53c\/task_environmental_tmp117.c\">Rohansicht<\/a><\/p>\n\n<p class=\"wp-block-paragraph\">Die Sensoren werden nach der Reihenfolge in der obigen Aufz\u00e4hlung priorisiert. <strong>TMP117<\/strong> wird zuerst versucht. Wenn der Sensor nach der Initialisierung keine Daten liefern kann, wird <strong>SHTC<\/strong> versucht, dann <strong>BME280<\/strong> usw. Es ist auch m\u00f6glich, zur Laufzeit ein neues Sensor-Backend auszuw\u00e4hlen. <\/p>\n\n<h3 class=\"wp-block-heading\">Konfiguration<\/h3>\n\n<p class=\"wp-block-paragraph\">Wir m\u00fcssen die Standardkonfiguration hinzuf\u00fcgen und das Kompilieren des Sensors f\u00fcr unsere Anwendung aktivieren. F\u00fcr die Benutzerkonfiguration f\u00fcgen wir hinzu <\/p>\n\n<pre class=\"wp-block-code\"><code>#define APPLICATION_ENVIRONMENTAL_TMP117_ENABLED      (1 &amp;&amp; RUUVI_BOARD_ENVIRONMENTAL_TMP117_PRESENT)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">zu <em>application_config.h<\/em><\/p>\n\n<p class=\"wp-block-paragraph\">Damit das <em>ruuvi.drivers.c<\/em>-Projekt nur die notwendigen Komponenten kompiliert, f\u00fcgen wir hinzu<\/p>\n\n<pre class=\"wp-block-code\"><code>#define RUUVI_INTERFACE_ENVIRONMENTAL_TMP117_ENABLED     APPLICATION_ENVIRONMENTAL_TMP117_ENABLED<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">zu <em>application_driver_configuration.h.<\/em> Die Konfigurationsdateien befinden sich in der oberen rechten Ecke des Anwendungsdiagramms.<\/p>\n\n<p class=\"wp-block-paragraph\">Schlie\u00dflich definieren wir die Standardkonfiguration in <em>application_mode_default.h<\/em>.<\/p>\n\n<pre class=\"wp-block-code\"><code>#ifndef APPLICATION_ENVIRONMENTAL_TMP117_DSP_FUNC\n#define APPLICATION_ENVIRONMENTAL_TMP117_DSP_FUNC   APPLICATION_ENVIRONMENTAL_DSPFUNC\n#endif\n\n#ifndef APPLICATION_ENVIRONMENTAL_TMP117_DSP_PARAM\n#define APPLICATION_ENVIRONMENTAL_TMP117_DSP_PARAM  APPLICATION_ENVIRONMENTAL_DSPPARAM\n#endif\n\n#ifndef APPLICATION_ENVIRONMENTAL_TMP117_MODE\n#define APPLICATION_ENVIRONMENTAL_TMP117_MODE       APPLICATION_ENVIRONMENTAL_MODE\n#endif\n\n#ifndef APPLICATION_ENVIRONMENTAL_TMP117_RESOLUTION\n#define APPLICATION_ENVIRONMENTAL_TMP117_RESOLUTION APPLICATION_ENVIRONMENTAL_RESOLUTION\n#endif\n\n#ifndef APPLICATION_ENVIRONMENTAL_TMP117_SAMPLERATE\n#define APPLICATION_ENVIRONMENTAL_TMP117_SAMPLERATE RUUVI_DRIVER_SENSOR_CFG_DEFAULT\n#endif\n\n#ifndef APPLICATION_ENVIRONMENTAL_TMP117_SCALE\n#define APPLICATION_ENVIRONMENTAL_TMP117_SCALE      APPLICATION_ENVIRONMENTAL_SCALE\n#endif<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/3ca31799890ada5358a3c3710ecf6fc0\/raw\/74be8dade838646b955ac6335a55576be057c3ac\/application_config_tmp117.h\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\">Diese Definitionen k\u00f6nnen in verschiedenen Anwendungsmoduskonfigurationsdateien \u00fcberschrieben werden.<\/p>\n\n<h3 class=\"wp-block-heading\">Sensoren vergleichen<\/h3>\n\n<p class=\"wp-block-paragraph\">Hier zweigen wir von der Master-Version der Ruuvi-Firmware ab. Die Master-Firmware hat einen <em>Heartbeat<\/em>, der die Sensordaten an Listener aktualisiert. Standardm\u00e4\u00dfig ist dieser Heartbeat <strong>BLE<\/strong>-Werbung, aber w\u00e4hrend einer <strong>GATT<\/strong>-Verbindung werden die Daten stattdessen \u00fcber den Nordic UART Service gesendet. Wir erstellen spezielle Logik, um den Sensor zu wechseln und die <strong>MAC<\/strong>-Adresse w\u00e4hrend der \u00dcbertragung zu \u00e4ndern, um Daten von verschiedenen Sensoren zu erhalten.   <\/p>\n\n<pre class=\"wp-block-code\"><code>static void select_next_backend()\n{\n  static uint8_t index = 0;\n  static const char list&#91;5]&#91;9] = { \"BME280\", \n                                   \"LIS2DH12\",\n                                   \"SHTCX\",\n                                   \"nRF5TMP\",\n                                   \"TMP117\"};\n  static uint8_t ids&#91;] = {0x80, 0x12, 0xC3, 0x52, 0x17};\n  uint8_t id;\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_ERROR_NOT_FOUND;\n  while(err_code == RUUVI_DRIVER_ERROR_NOT_FOUND)\n  {\n    err_code = task_environmental_backend_set(list&#91;index]);\n    id = ids&#91;index++];\n    index = index % sizeof(ids);\n  }\n\n  uint64_t address;\n  uint64_t mask = 0xFFFFFFFFFFFFFF00;\n  err_code |= ruuvi_interface_communication_radio_address_get(&amp;address);\n  address &amp;= mask;\n  address |= id;\n  err_code |= task_advertisement_stop();\n  err_code |= ruuvi_interface_communication_radio_address_set(address);\n  RUUVI_DRIVER_ERROR_CHECK(err_code, ~RUUVI_DRIVER_ERROR_FATAL);\n}\n\nstatic void heartbeat_send(void* p_event_data, uint16_t event_size)\n{\n  select_next_backend();\n\n  ruuvi_interface_communication_message_t msg = {0};\n  task_sensor_encode_to_5((uint8_t*)&amp;msg.data);\n  msg.data_length = m_heartbeat_data_max_len;\n  task_advertisement_start();\n  ruuvi_driver_status_t err_code = RUUVI_DRIVER_ERROR_INTERNAL;\n  if(NULL != heartbeat_target) \n  { \n    err_code = heartbeat_target(&amp;msg); \n  }\n  if(RUUVI_DRIVER_SUCCESS == err_code) { ruuvi_interface_watchdog_feed(); }\n  RUUVI_DRIVER_ERROR_CHECK(err_code, ~RUUVI_DRIVER_ERROR_FATAL);\n}<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/gist.githubusercontent.com\/ojousima\/5678c1563cdb3665c044250ee77257b8\/raw\/47e2cb3fa0fd4eab404fe061f2671ce3676c1ba8\/sensord_comparison.c\">Rohansicht<\/a><\/p>\n\n<p class=\"has-text-align-center wp-block-paragraph\"><em>Sensoren werden durchlaufen, um vergleichbare Daten zu erhalten<\/em><\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"327\" src=\"https:\/\/ruuvi.com\/i\/u\/temperature-graph-1024x327.png\" alt=\"Temperaturdiagramm\" class=\"wp-image-4027\" srcset=\"https:\/\/ruuvi.com\/i\/u\/temperature-graph-1024x327.png 1024w, https:\/\/ruuvi.com\/i\/u\/temperature-graph-450x144.png 450w, https:\/\/ruuvi.com\/i\/u\/temperature-graph-768x246.png 768w, https:\/\/ruuvi.com\/i\/u\/temperature-graph-600x192.png 600w, https:\/\/ruuvi.com\/i\/u\/temperature-graph.png 1107w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Vorhandene Datenerfassungs- und Plotting-Software funktioniert hierf\u00fcr einwandfrei, wir sortieren die Daten einfach nach MAC-Adresse<\/figcaption><\/figure><\/div>\n\n<h2 class=\"wp-block-heading\">Letzte Feinheiten<\/h2>\n\n<h3 class=\"wp-block-heading\">Das Gute zur\u00fcck zum Master mergen<\/h3>\n\n<p class=\"wp-block-paragraph\">W\u00e4hrend der Entwicklung der Sensorvergleichs-FW habe ich einige Fehler in der Firmware gefunden. Wenn der Beschleunigungssensor nicht initialisiert werden kann, steigt ein Fehler aus der Sensordatencodierung auf und die Anwendung betrachtet dies als fatales Problem und startet neu. Wir m\u00f6chten jedoch in der Lage sein, die Firmware ohne Beschleunigungssensor zu verwenden, also betrachten wir es einfach als Warnung und lassen die Anwendung fortfahren.  <\/p>\n\n<p class=\"wp-block-paragraph\">Die Sensordateninitialisierung f\u00fcr die \u00dcbertragung verwendete Dummy-Werte. Wir \u00e4ndern die Sensordateninitialisierung so, dass sie dieselbe Logik wie die Anwendungs\u00fcbertragung verwendet. Dies hilft, Probleme mit dem Messsequenzz\u00e4hler usw. zu vermeiden. <\/p>\n\n<p class=\"wp-block-paragraph\">Lass uns die Unterschiede mit git status \u00fcberpr\u00fcfen:<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"492\" height=\"172\" src=\"https:\/\/ruuvi.com\/i\/u\/git-status.png\" alt=\"Git-Status\" class=\"wp-image-4028\" srcset=\"https:\/\/ruuvi.com\/i\/u\/git-status.png 492w, https:\/\/ruuvi.com\/i\/u\/git-status-450x157.png 450w\" sizes=\"auto, (max-width: 492px) 100vw, 492px\" \/><figcaption>Wir m\u00f6chten die Werbungsfixes ausw\u00e4hlen, die Umgebungsaufgabe mit TMP und die aktualisierte Konfiguration hinzuf\u00fcgen. Wir m\u00f6chten auch das Beschleunigungssensor-Update ausw\u00e4hlen, um dem Programm zu erm\u00f6glichen, ohne Beschleunigungssensor fortzufahren. <\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Wir committen die Dateien in vier Gruppen: <em>task_advertisement<\/em> ist eine Gruppe, <em>task_environmental<\/em> und <em>configuration<\/em> ist die zweite und <em>task_acceleration<\/em> ist die dritte. Wir m\u00f6chten die <em>task_communication<\/em>-\u00c4nderungen zur\u00fccklassen, da sie nur f\u00fcr diesen Branch waren, aber wir committen sie in der vierten Gruppe f\u00fcr die zuk\u00fcnftige Verwendung. <\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"494\" height=\"156\" src=\"https:\/\/ruuvi.com\/i\/u\/branch-for-future-usage.png\" alt=\"Branch f&#xFC;r zuk&#xFC;nftige Verwendung.\" class=\"wp-image-4029\" srcset=\"https:\/\/ruuvi.com\/i\/u\/branch-for-future-usage.png 494w, https:\/\/ruuvi.com\/i\/u\/branch-for-future-usage-450x142.png 450w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><figcaption>Log der Commits nach dem Branching<\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Unsere Sensorvergleichs-FW wurde auf den Master rebased, sodass alle Unterschiede auf der aktuellen Version der Firmware aufbauen. Jetzt m\u00f6chten wir die 3 Commits <em>086f0ce<\/em>, <em>73738f9<\/em> und <em>98b07ca<\/em> zur\u00fcck zum Master-Branch bringen. <\/p>\n\n<p class=\"wp-block-paragraph\">Wir f\u00fchren aus<\/p>\n\n<pre class=\"wp-block-code\"><code>git checkout master\ngit cherry-pick 086f0ce^..98b07ca<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">um die Commits zu erhalten. Es stellt sich heraus, dass der letzte Commit nichts im Vergleich zum Master-Branch hinzuzuf\u00fcgen hat. Die Beschleunigungssensorinitialisierung war wahrscheinlich irgendwo auf dem Weg kaputt gegangen. <\/p>\n\n<p class=\"wp-block-paragraph\">Jetzt sieht unser Master so aus:<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"494\" height=\"88\" src=\"https:\/\/ruuvi.com\/i\/u\/our-master.png\" alt=\"Wie unser Master aussieht\" class=\"wp-image-4030\" srcset=\"https:\/\/ruuvi.com\/i\/u\/our-master.png 494w, https:\/\/ruuvi.com\/i\/u\/our-master-450x80.png 450w\" sizes=\"auto, (max-width: 494px) 100vw, 494px\" \/><figcaption>Meine Commit-Messages lassen zu w\u00fcnschen \u00fcbrig \u2013 warum gibt es \u201eenable\u201c und \u201esupport\u201c getrennt? Ich wei\u00df warum, aber wenn man ins Log schaut, hat ein anderer Entwickler keine Ahnung. <\/figcaption><\/figure><\/div>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes rebasen wir den Sensorvergleichs-Branch auf den Master, um ihn auf dem neuesten Stand zu halten.<\/p>\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"458\" height=\"105\" src=\"https:\/\/ruuvi.com\/i\/u\/master-up-to-date.png\" alt=\"Wie der Master aussieht, wenn er auf dem neuesten Stand ist\" class=\"wp-image-4031\" srcset=\"https:\/\/ruuvi.com\/i\/u\/master-up-to-date.png 458w, https:\/\/ruuvi.com\/i\/u\/master-up-to-date-450x103.png 450w\" sizes=\"auto, (max-width: 458px) 100vw, 458px\" \/><figcaption>Fertig, unser Sensorvergleich ist jetzt auf dem Master aufgebaut, der die zusammengef\u00fchrte TMP117-Unterst\u00fctzung hat.<\/figcaption><\/figure><\/div>\n\n<h3 class=\"wp-block-heading\">Code formatieren und Doxygen-Seiten generieren<\/h3>\n\n<p class=\"wp-block-paragraph\">Damit der Stil im Projekt konsistent bleibt, verwenden wir <a href=\"http:\/\/astyle.sourceforge.net\">Artistic Style<\/a>, um den Code in ein einheitliches Format zu bringen. Es ist nicht ganz so, wie ich es gern h\u00e4tte, weil Kommentare am Zeilenende zur Zeilenl\u00e4nge z\u00e4hlen und mich das praktisch dazu zwingt, keine Kommentare in Codezeilen zu verwenden, um seltsame Einr\u00fcckungen zu vermeiden \u2013 aber es ist definitiv besser als nichts. Wir gehen die Submodule separat durch und starten mit <em>ruuvi.drivers.c<\/em>.  <\/p>\n\n<pre class=\"wp-block-code\"><code>astyle --project=.astylerc --recursive \".\/interfaces\/*.c\"\nastyle --project=.astylerc --recursive \".\/interfaces\/*.h\"\nastyle --project=.astylerc --recursive \".\/nrf5_sdk15_platform\/*.c\"\nastyle --project=.astylerc --recursive \".\/nrf5_sdk15_platform\/*.h\"<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Als N\u00e4chstes pr\u00fcfen wir mit <a href=\"http:\/\/www.doxygen.nl\">Doxygen<\/a>, ob die Kommentare vollst\u00e4ndig und aktuell sind. Doxygen durchsucht den Quellcode nach Kommentaren und erzeugt HTML- und PDF-Dokumentation zu Funktionen, Strukturen, Enumerationen, Makros und so weiter. Die Doxygen-Generierung ist ganz einfach:  <\/p>\n\n<pre class=\"wp-block-code\"><code>doxygen<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Die Generierung erzeugt die Datei <em>doxygen.error<\/em> mit 55 Eintr\u00e4gen. Wir bauen diese technische Schuld heute ein St\u00fcck weit ab, stellen sicher, dass keiner dieser Fehler aus <strong>TMP117<\/strong>-Dateien stammt, und beheben die erste Datei mit Fehlern \u2013 <em>ruuvi_interface_shtcx.c<\/em>. <\/p>\n\n<p class=\"wp-block-paragraph\">Wir wiederholen diesen Prozess im Hauptprojektordner, auch wenn es dort noch keine Doxygen-Unterst\u00fctzung gibt.<\/p>\n\n<h3 class=\"wp-block-heading\">Arbeit teilen<\/h3>\n\n<p class=\"wp-block-paragraph\">Da wir noch in der Alpha sind und es \u00fcberall deutliche Hinweise gibt, dass das Projekt in Entwicklung ist, pushen wir einfach direkt auf master und lassen <a href=\"https:\/\/travis-ci.org\">Travis<\/a> und Jenkins entscheiden, ob das Projekt bereit ist.<\/p>\n\n<p class=\"wp-block-paragraph\">Travis baut die Doxygen-Dokumentation f\u00fcr <em>ruuvi.drivers.c<\/em> und pusht die fertigen Dokumente in den Branch gh-pages. Jenkins baut die Firmware-Varianten f\u00fcr die Boards und stellt die gebauten Binaries online f\u00fcr alle bereit. <\/p>\n\n<p class=\"wp-block-paragraph\">In diesem Fall entdeckt Jenkins einen Fehler: Wir haben <em>ruuvi_interface_tmp117.c <\/em>nicht zu den GCC-Quellen in der Datei <em>gcc_sources.make<\/em> hinzugef\u00fcgt. Nachdem wir die Datei erg\u00e4nzt haben, k\u00f6nnen wir es erneut versuchen. <\/p>\n\n<pre class=\"wp-block-code\"><code>Compiling file: ruuvi_interface_tmp117.c\n..\/..\/..\/ruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c: In function 'ruuvi_interface_tmp117_dsp_get':\n..\/..\/..\/ruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c:508:25: error: variable 'err_code' set but not used &#91;-Werror=unused-but-set-variable]\n   ruuvi_driver_status_t err_code;\n                         ^~~~~~~~\n..\/..\/..\/ruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c:534:1: error: control reaches end of non-void function &#91;-Werror=return-type]\n }\n ^\nAt top level:\n..\/..\/..\/ruuvi.drivers.c\/interfaces\/environmental\/ruuvi_interface_tmp117.c:42:30: error: 'tmp117_soft_reset' defined but not used &#91;-Werror=unused-function]\n static ruuvi_driver_status_t tmp117_soft_reset(void)\n                              ^~~~~~~~~~~~~~~~~\ncc1: all warnings being treated as errors<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Hier k\u00f6nnen wir noch ein paar weitere Fehler abfangen, die die statische Analyse von GCC findet. Eine unserer Funktionen hat vergessen, den Fehlercode tats\u00e4chlich zur\u00fcckzugeben, und unsere Initialisierung hat den <strong>TMP117<\/strong> nicht in einen definierten Zustand zur\u00fcckversetzt. <\/p>\n\n<p class=\"wp-block-paragraph\">Nach den Fixes ist die Dokumentation automatisch unter <a href=\"https:\/\/ruuvi.github.io\/ruuvi.drivers.c\/group___t_m_p117.html\">github.io<\/a> verf\u00fcgbar, und die Builds sind unter <a href=\"https:\/\/jenkins.ruuvi.com\/job\/ruuvi.firmware.c\/67\/\">jenkins.ruuvi.com<\/a> verf\u00fcgbar.<\/p>\n\n<h3 class=\"wp-block-heading\">Stromverbrauch<\/h3>\n\n<p class=\"wp-block-paragraph\">Dieses Mal arbeiten wir an einem experimentellen Board und werden nicht verifizieren, ob der finale Stromverbrauch in einem akzeptablen Bereich liegt. Bevor wir den Code jedoch an Kunden ausliefern, achten wir der Umwelt zuliebe darauf und pr\u00fcfen, dass der Stromverbrauch nicht \u00fcberm\u00e4\u00dfig ist. <\/p>\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n<p class=\"wp-block-paragraph\">Nach einem langen Beitrag haben wir einen neuen Sensor zur Ruuvi Firmware hinzugef\u00fcgt. Das Wichtigste in diesem Beitrag waren allerdings nicht die Details, wie man etwas umsetzt. Die wichtigsten Erkenntnisse sind:  <\/p>\n\n<ol class=\"wp-block-list\"><li>Achte auf deine Architektur. Beim Programmieren hatte der Treiber viel Komplexit\u00e4t, aber sobald der Treiber fertig war, brauchten wir weniger als 100 Zeilen Code, um den Sensor zu initialisieren, die Sensorkonfiguration aus dem Flash zu laden oder die Standardkonfiguration zu verwenden, wenn im Flash keine Konfiguration vorhanden ist, und die kodierten Daten je nach Programmzustand \u00fcber Bluetooth-Advertisements oder GATT zu senden. Und das funktioniert \u00fcber 3 verschiedene Boards, 2 verschiedene MCUs und kann mit einem fehlenden Sensor sauber umgehen \u2013 mit Fallback auf den n\u00e4chsten Sensor. Der Code profitiert au\u00dferdem von allen zuk\u00fcnftigen Verbesserungen und Bugfixes in der gemeinsamen Logik.   <\/li><li>Automatische Tests und wiederverwendbare Interfaces k\u00f6nnen dir den Tag retten. Wir hatten den High-Level-Zugriff auf den Sensor und automatische Tests bereits definiert, um den Sensortreiber \u00fcber das Interface zu verifizieren. Die automatischen Tests haben 7 Bugs in der Implementierung gefunden, und eine weitere statische Analyse durch GCC hat einige Randf\u00e4lle entdeckt, etwa dass die Initialisierung den Sensor nicht wirklich in einen definierten Zustand zur\u00fccksetzt. Die automatische Kompilierung hat au\u00dferdem ein Problem erkannt, bei dem das Projekt nach dem Push nicht mehr kompilierbar war.   <\/li><\/ol>\n\n<p class=\"wp-block-paragraph\">Das war\u2019s f\u00fcr dieses Mal. Wenn du dich fragst, was es mit diesen mysteri\u00f6sen Kaarle- und Keijo-Boards auf sich hat, dann trag dich unten auf der Startseite in die <a href=\"https:\/\/ruuvi.com\/de\/\">Ruuvi-Mailingliste<\/a> ein und erfahre es als einer der Ersten \ud83d\ude09<\/p>\n\n<p class=\"wp-block-paragraph\">RuuviTags eignen sich auch hervorragend als Black-Friday- und Weihnachtsgeschenke, und ihre Verk\u00e4ufe unterst\u00fctzen die Erstellung dieser Beitr\u00e4ge. Wenn dir die Inhalte gefallen, teile Ruuvi mit deiner Familie! Und jetzt: <strong>Measure Your World.<\/strong> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Heute gehen wir durch, wie man einen neuen Sensor zur Ruuvi-Firmware hinzuf\u00fcgt. Dieser Beitrag baut auf der RuuviFW-Version 3.28.0 auf, die auf GitHub verf\u00fcgbar ist. Das Projekt wird mit Segger Embedded Studio Nordic Semiconductor Version 4.18 kompiliert. Die nRF SDK-Version ist nRF5_SDK_15.3.0_59ac345. Detaillierte Einrichtungsanweisungen findest du im Beitrag Ruuvi-Firmware \u2013 Teil 1. Sensor Der Sensor, [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":135682,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[324],"tags":[],"class_list":["post-135681","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>Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi<\/title>\n<meta name=\"description\" content=\"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.\" \/>\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\/ruuvi-firmware-neuen-sensor-hinzufuegen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi\" \/>\n<meta property=\"og:description\" content=\"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/\" \/>\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=\"2019-11-18T11:58:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-11T04:31:50+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png\" \/>\n\t<meta property=\"og:image:width\" content=\"800\" \/>\n\t<meta property=\"og:image:height\" content=\"500\" \/>\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=\"31\u00a0Minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/\"},\"author\":{\"name\":\"Otso Jousimaa\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"headline\":\"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen\",\"datePublished\":\"2019-11-18T11:58:00+00:00\",\"dateModified\":\"2026-06-11T04:31:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/\"},\"wordCount\":2771,\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/tmp117-by-texas-instruments.png\",\"articleSection\":[\"Ruuvi-Software-Artikel\"],\"inLanguage\":\"de\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/\",\"name\":\"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/tmp117-by-texas-instruments.png\",\"datePublished\":\"2019-11-18T11:58:00+00:00\",\"dateModified\":\"2026-06-11T04:31:50+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/#\\\/schema\\\/person\\\/143b8e2a095f1e6484b9186673c9ec00\"},\"description\":\"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/tmp117-by-texas-instruments.png\",\"contentUrl\":\"https:\\\/\\\/ruuvi.com\\\/i\\\/u\\\/tmp117-by-texas-instruments.png\",\"width\":800,\"height\":500,\"caption\":\"TMP117 von Texas Instruments\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/ruuvi-firmware-neuen-sensor-hinzufuegen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ruuvi.com\\\/de\\\/front\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen\"}]},{\"@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":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi","description":"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.","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\/ruuvi-firmware-neuen-sensor-hinzufuegen\/","og_locale":"de_DE","og_type":"article","og_title":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi","og_description":"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.","og_url":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/","og_site_name":"Ruuvi","article_publisher":"https:\/\/www.facebook.com\/ruuvi.cc","article_published_time":"2019-11-18T11:58:00+00:00","article_modified_time":"2026-06-11T04:31:50+00:00","og_image":[{"width":800,"height":500,"url":"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.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":"31\u00a0Minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#article","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/"},"author":{"name":"Otso Jousimaa","@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"headline":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen","datePublished":"2019-11-18T11:58:00+00:00","dateModified":"2026-06-11T04:31:50+00:00","mainEntityOfPage":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/"},"wordCount":2771,"image":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png","articleSection":["Ruuvi-Software-Artikel"],"inLanguage":"de"},{"@type":"WebPage","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/","url":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/","name":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen - Ruuvi","isPartOf":{"@id":"https:\/\/ruuvi.com\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#primaryimage"},"image":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#primaryimage"},"thumbnailUrl":"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png","datePublished":"2019-11-18T11:58:00+00:00","dateModified":"2026-06-11T04:31:50+00:00","author":{"@id":"https:\/\/ruuvi.com\/de\/#\/schema\/person\/143b8e2a095f1e6484b9186673c9ec00"},"description":"Hinzuf\u00fcgen eines neuen Sensors zur Firmware des RuuviTag. Beispiel mit dem hochpr\u00e4zisen Texas Instruments TMP117-Sensor. Kostenloser Code kann am Ende heruntergeladen werden.","breadcrumb":{"@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#primaryimage","url":"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png","contentUrl":"https:\/\/ruuvi.com\/i\/u\/tmp117-by-texas-instruments.png","width":800,"height":500,"caption":"TMP117 von Texas Instruments"},{"@type":"BreadcrumbList","@id":"https:\/\/ruuvi.com\/de\/ruuvi-firmware-neuen-sensor-hinzufuegen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ruuvi.com\/de\/front\/"},{"@type":"ListItem","position":2,"name":"Ruuvi-Firmware: Einen neuen Sensor hinzuf\u00fcgen"}]},{"@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\/135681","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=135681"}],"version-history":[{"count":1,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135681\/revisions"}],"predecessor-version":[{"id":135688,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/posts\/135681\/revisions\/135688"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media\/135682"}],"wp:attachment":[{"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/media?parent=135681"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/categories?post=135681"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ruuvi.com\/de\/wp-json\/wp\/v2\/tags?post=135681"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}