docs: add my first sensors walk through

Add a walk through for a beginner to using entity-manager and
dbus-sensors.  This guide is meant to provide a detailed walk through of
a very basic example.

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I79413c11f1065a0056bef838d700e9a4ea92cff0
diff --git a/README.md b/README.md
index 001d29e..e188efa 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,12 @@
 
 
 
+## Configuration HowTos
+
+If you're just getting started and your goal is to add sensors dynamically,
+check out [My First Sensors](docs/my_first_sensors.md)
+
+
 ## Configuration Records - Baseboard Example
 
 Required fields are name, probe and exposes.
diff --git a/docs/my_first_sensors.md b/docs/my_first_sensors.md
new file mode 100644
index 0000000..092808d
--- /dev/null
+++ b/docs/my_first_sensors.md
@@ -0,0 +1,253 @@
+# 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, and this is beyond
+this guide.
+
+For the sake of this very simple 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 this guide, but for this
+example 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": "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.
+
+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
+
+root@semitruck:~# busctl tree --no-pager 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 this,
+will trigger FruDevice to scan those new buses for more devices.