# My First Sensors This document is meant to bring you from nothing to using Entity-Manager with Dbus-Sensors to populate a plug-in card's sensor values on dbus. Once the sensor values are on dbus, they can be read via IPMI or Redfish (doing so is beyond the scope of this guide). For the sake of this example, let's pretend there is a PCIe card that exposes an 24c02 eeprom and a tmp441 sensor. The PCIe slots are behind an smbus mux on the motherboard and are in a device-tree such as this: ``` aliases { i2c16 = &i2c_pe0; i2c17 = &i2c_pe1; i2c18 = &i2c_pe2; i2c19 = &i2c_pe3; }; ... &i2c1 { status = "okay"; i2c-switch@71 { compatible = "nxp,pca9546"; reg = <0x71>; #address-cells = <1>; #size-cells = <0>; i2c-mux-idle-disconnect; i2c_pe0: i2c@0 { #address-cells = <1>; #size-cells = <0>; reg = <0>; }; i2c_pe1: i2c@1 { #address-cells = <1>; #size-cells = <0>; reg = <1>; }; i2c_pe2: i2c@2 { #address-cells = <1>; #size-cells = <0>; reg = <2>; }; i2c_pe3: i2c@3 { #address-cells = <1>; #size-cells = <0>; reg = <3>; }; }; }; ``` The first daemon of interest that will run is the FruDevice portion of Entity-Manager. The exact layout of a FRU is beyond the scope of this guide, but assume the PCIe card's eeprom holds the following information: ``` Product: MANUFACTURER "Awesome" PART_NUMBER "12345" PRODUCT_NAME "Super Great" SERIAL_NUMBER "12312490840" ``` The FruDevice daemon will walk all i2c buses and attempt to find FRU contents at responsive smbus addresses. When if finds a FRU it will parse the contents and publish them to dbus keying off the most prominent name field. In this case, it found two of the cards. One at bus 18 and the other at 19. The dbus tree for this will look like: ``` ``` ~# busctl tree --no-pager xyz.openbmc_project.FruDevice `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/FruDevice |-/xyz/openbmc_project/FruDevice/Super_Great |-/xyz/openbmc_project/FruDevice/Super_Great_0 ``` The dbus path for each instance is unimportant beyond needing to be unique. Digging into one of these FRUs we see: ``` ~# busctl introspect --no-pager xyz.openbmc_project.FruDevice \ /xyz/openbmc_project/FruDevice/Super_Great NAME TYPE SIGNATURE RESULT/VALUE FLAGS org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - xyz.openbmc_project.FruDevice interface - - - .ADDRESS property u 80 emits-change .BUS property u 18 emits-change .Common_Format_Version property s "1" emits-change .PRODUCT_ASSET_TAG property s "--" emits-change .PRODUCT_FRU_VERSION_ID property s "??????" emits-change .PRODUCT_LANGUAGE_CODE property s "0" emits-change .PRODUCT_MANUFACTURER property s "Awesome" emits-change .PRODUCT_PART_NUMBER property s "12345" emits-change .PRODUCT_PRODUCT_NAME property s "Super Great" emits-change .PRODUCT_SERIAL_NUMBER property s "12312490840" emits-change .PRODUCT_VERSION property s "0A" emits-change ``` Ok, now you can find the cards, but what about the temperature sensors on each of them? Entity-Manager provides a very powerful mechanism for querying various information, but our goal is simple. If we find the card, we want to add the device to the system and tell dbus-sensors that there is a hwmon temperature sensor available. We start with a simple hardware profile. We know that if the card's bus is identified we know the address of the temperature sensor is 0x4c. ``` { "Exposes": [ { "Address": "$address", "Bus": "$bus", "Name": "$bus great eeprom", "Type": "EEPROM_24C02" }, { "Address": "0x4c", "Bus": "$bus", "Name": "$bus great local", "Name1": "$bus great ext", "Type": "TMP441" } ], "Name": "$bus Great Card", "Probe": "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': 'Super Great'})", "Type": "Board" } ``` There's a lot going on in the above hardware profile, and they can become considerably more complex. Firstly, let's start with the `Probe` field. This is a way of defining under what circumstances this hardware profile is applied. In this case, we want the hardware profile to be applied when a Fru is found with the field `PRODUCT_PRODUCT_NAME` holding the value `Super Great`. In our system, this will match twice. When the probe has matched the information from that device is then swapped into the hardware profile via the templated variables, such as `$bus` or `$address`. We then shift our focus to the `Exposes` field. This lists the entities that are added when this hardware profile is loaded. The field is optional and there is a wide variety of entities that can be added this way. In our example we only care about the eeprom and the temperature sensor. The `Type` field is checked against a device export map and if it matches a known device, it'll attempt to install the device. Be noticed that dbus only allows an interface name as an dot delimited string with each truncated substring starting with alphabets(a-z, A-Z). So the Type is intensionally renamed as EEPROM_24C02. It is safe to do so since Entity manager types are not required to be 1:1 with Linux types. For the card found on bus 18: ``` echo "24c02 0x50 > /sys/bus/i2c/devices/i2c-18/new_device" echo "tmp441 0x4c > /sys/bus/i2c/devices/i2c-18/new_device" ``` Beyond this, it also publishes to dbus a configuration: ``` ~# busctl tree --no-pager xyz.openbmc_project.EntityManager `-/xyz `-/xyz/openbmc_project |-/xyz/openbmc_project/EntityManager `-/xyz/openbmc_project/inventory `-/xyz/openbmc_project/inventory/system `-/xyz/openbmc_project/inventory/system/board |-/xyz/openbmc_project/inventory/system/board/18_Great_Card | |-/xyz/openbmc_project/inventory/system/board/18_Great_Card/18_great_local |-/xyz/openbmc_project/inventory/system/board/19_Great_Card | |-/xyz/openbmc_project/inventory/system/board/19_Great_Card/19_great_local ~# busctl introspect --no-pager xyz.openbmc_project.EntityManager \ /xyz/openbmc_project/inventory/system/board/18_Great_Card/18_great_local NAME TYPE SIGNATURE RESULT/VALUE FLAGS org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - xyz.openbmc_project.Configuration.TMP441 interface - - - .Address property t 76 emits-change .Bus property t 18 emits-change .Name property s "18 great local" emits-change .Name1 property s "18 great ext" emits-change .Type property s "TMP441" emits-change ``` The dbus-sensors suite of daemons each run searching for a specific type of sensor. In this case the hwmon temperature sensor daemon will recognize the configuration interface: `xyz.openbmc_project.Configuration.TMP441`. It will look up the device on i2c and see there is a hwmon instance, and map `temp1_input` to `Name` and since there is also `Name1` it'll map `temp2_input`. ``` ~# busctl tree --no-pager Service xyz.openbmc_project.HwmonTempSensor `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/sensors `-/xyz/openbmc_project/sensors/temperature |-/xyz/openbmc_project/sensors/temperature/18_great_local |-/xyz/openbmc_project/sensors/temperature/18_great_ext |-/xyz/openbmc_project/sensors/temperature/19_great_local |-/xyz/openbmc_project/sensors/temperature/19_great_ext ~# busctl introspect --no-pager xyz.openbmc_project.HwmonTempSensor \ /xyz/openbmc_project/sensors/temperature/18_great_local NAME TYPE SIGNATURE RESULT/VALUE FLAGS org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - org.openbmc.Associations interface - - - .associations property a(sss) 1 "chassis" "all_sensors" "/xyz/openb... emits-change xyz.openbmc_project.Sensor.Value interface - - - .MaxValue property d 127 emits-change .MinValue property d -128 emits-change .Value property d 31.938 emits-change writable ``` There you are! You now have the two sensors from the two card instances on dbus. This can be more complex, for instance if your card has a mux you can add it to the configuration, which will trigger FruDevice to scan those new buses for more devices.