incremental
diff --git a/boost-dbus/CMakeLists.txt b/boost-dbus/CMakeLists.txt
index 9d07a5b..736d030 100644
--- a/boost-dbus/CMakeLists.txt
+++ b/boost-dbus/CMakeLists.txt
@@ -20,7 +20,11 @@
 
 ###############
 # import Boost
+add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions(-DBOOST_ALL_NO_LIB)
 find_package(Boost REQUIRED)
+
 include_directories(${Boost_INCLUDE_DIRS})
 link_directories(${Boost_LIBRARY_DIRS})
 
diff --git a/boost-dbus/include/dbus/element.hpp b/boost-dbus/include/dbus/element.hpp
index 276b593..32cdcdc 100644
--- a/boost-dbus/include/dbus/element.hpp
+++ b/boost-dbus/include/dbus/element.hpp
@@ -8,7 +8,9 @@
 
 #include <dbus/dbus.h>
 #include <string>
+#include <vector>
 #include <boost/cstdint.hpp>
+#include <boost/variant.hpp>
 
 namespace dbus {
 
@@ -31,6 +33,11 @@
 // unix_fd
 
 typedef std::string string;
+
+typedef boost::variant<std::string, bool, byte, int16, uint16, int32, uint32, int64,
+                       uint64, double>
+    dbus_variant;
+
 struct object_path {
   string value;
 };
@@ -97,6 +104,16 @@
   static const int code = DBUS_TYPE_STRING;
 };
 
+template <typename Element>
+struct element<std::vector<Element>> {
+  static const int code = DBUS_TYPE_ARRAY;
+};
+
+template <>
+struct element<dbus_variant> {
+  static const int code = DBUS_TYPE_VARIANT;
+};
+
 template <>
 struct element<object_path> {
   static const int code = DBUS_TYPE_OBJECT_PATH;
diff --git a/boost-dbus/include/dbus/impl/message_iterator.hpp b/boost-dbus/include/dbus/impl/message_iterator.hpp
index 44bcf2e..6969b8b 100644
--- a/boost-dbus/include/dbus/impl/message_iterator.hpp
+++ b/boost-dbus/include/dbus/impl/message_iterator.hpp
@@ -34,7 +34,8 @@
 
   bool next();
   bool has_next();
-  int get_arg_type();
+  char get_arg_type();
+  int get_element_count();
 
   void get_basic(void *value);
 
diff --git a/boost-dbus/include/dbus/impl/message_iterator.ipp b/boost-dbus/include/dbus/impl/message_iterator.ipp
index eb2584f..034f658 100644
--- a/boost-dbus/include/dbus/impl/message_iterator.ipp
+++ b/boost-dbus/include/dbus/impl/message_iterator.ipp
@@ -58,7 +58,12 @@
   return dbus_message_iter_has_next(&DBusMessageIter_);
 }
 
-inline int message_iterator::get_arg_type()
+inline int message_iterator::get_element_count()
+{
+  return dbus_message_iter_get_element_count(&DBusMessageIter_);
+}
+
+inline char message_iterator::get_arg_type()
 {
   return dbus_message_iter_get_arg_type(&DBusMessageIter_);
 }
diff --git a/boost-dbus/include/dbus/message.hpp b/boost-dbus/include/dbus/message.hpp
index aa5e89c..695e1fc 100644
--- a/boost-dbus/include/dbus/message.hpp
+++ b/boost-dbus/include/dbus/message.hpp
@@ -104,6 +104,7 @@
   struct packer {
     impl::message_iterator iter_;
     packer(message& m) { impl::message_iterator::init_append(m, iter_); }
+    packer(){};
     template <typename Element>
     packer& pack(const Element& e) {
       return *this << e;
@@ -112,6 +113,7 @@
   struct unpacker {
     impl::message_iterator iter_;
     unpacker(message& m) { impl::message_iterator::init(m, iter_); }
+    unpacker() {}
 
     template <typename Element>
     unpacker& unpack(Element& e) {
@@ -147,16 +149,106 @@
   return p;
 }
 
+template <typename Key, typename Value>
+message::packer& operator<<(message::packer& p,
+                            const std::vector<std::pair<Key, Value>>& v) {
+  message::packer sub;
+  char signature[] = {'{', element<Key>::code, element<Value>::code, '}', 0};
+
+  p.iter_.open_container(DBUS_TYPE_ARRAY, signature, sub.iter_);
+  for (auto& element : v) {
+    sub << element;
+  }
+
+  p.iter_.close_container(sub.iter_);
+  return p;
+}
+
+template <typename Element>
+message::packer& operator<<(message::packer& p, const std::vector<Element>& v) {
+  message::packer sub;
+  char signature[] = {element<Element>::code, 0};
+  p.iter_.open_container(element<std::vector<Element>>::code, signature,
+                         sub.iter_);
+  for (auto& element : v) {
+    sub << element;
+  }
+
+  p.iter_.close_container(sub.iter_);
+  return p;
+}
+
 inline message::packer& operator<<(message::packer& p, const char* c) {
   p.iter_.append_basic(element<string>::code, &c);
   return p;
 }
 
+template <typename Key, typename Value>
+inline message::packer& operator<<(message::packer& p,
+                                   const std::pair<Key, Value> element) {
+  message::packer dict_entry;
+  p.iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_);
+  dict_entry << element.first;
+  dict_entry << element.second;
+  p.iter_.close_container(dict_entry.iter_);
+  return p;
+}
+
 inline message::packer& operator<<(message::packer& p, const string& e) {
   const char* c = e.c_str();
   return p << c;
 }
 
+inline message::packer& operator<<(message::packer& p, const dbus_variant& v) {
+  message::packer sub;
+  char type = 0;
+  // TODO(ed) there must be a better (more typesafe) way to do this
+  switch (v.which()) {
+    case 0:
+      type = element<std::string>::code;
+      break;
+    case 1:
+      type = element<bool>::code;
+      break;
+    case 2:
+      type = element<byte>::code;
+      break;
+    case 3:
+      type = element<int16>::code;
+      break;
+    case 4:
+      type = element<uint16>::code;
+      break;
+    case 5:
+      type = element<int32>::code;
+      break;
+    case 6:
+      type = element<uint32>::code;
+      break;
+    case 7:
+      type = element<int64>::code;
+      break;
+    case 8:
+      type = element<uint64>::code;
+      break;
+    case 9:
+      type = element<double>::code;
+      break;
+
+    default:
+      // TODO(ed) throw exception
+      break;
+  }
+  char signature[] = {type, 0};
+
+  p.iter_.open_container(element<dbus_variant>::code, signature, sub.iter_);
+  boost::apply_visitor([&](auto val) { sub << val; }, v);
+  // sub << element;
+  p.iter_.close_container(sub.iter_);
+
+  return p;
+}
+
 template <typename Element>
 message::unpacker operator>>(message m, Element& e) {
   return message::unpacker(m).unpack(e);
@@ -178,32 +270,98 @@
   return u;
 }
 
+inline message::unpacker& operator>>(message::unpacker& u, dbus_variant& v) {
+  message::unpacker sub;
+  u.iter_.recurse(sub.iter_);
+
+  auto arg_type = sub.iter_.get_arg_type();
+  // sub.iter_.get_basic(&c);
+  // Todo(ed) find a better way to do this lookup table
+  switch (arg_type) {
+    case element<std::string>::code: {
+      std::string s;
+      sub >> s;
+      v = s;
+    } break;
+    case element<bool>::code: {
+      bool b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<byte>::code: {
+      byte b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<int16>::code: {
+      int16 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<uint16>::code: {
+      uint16 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<int32>::code: {
+      int32 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<uint32>::code: {
+      uint32 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<int64>::code: {
+      int64 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<uint64>::code: {
+      uint64 b;
+      sub >> b;
+      v = b;
+    } break;
+    case element<double>::code: {
+      double b;
+      sub >> b;
+      v = b;
+    } break;
+
+    default:
+      // TODO(ed) throw exception
+      break;
+  }
+  u.iter_.next();
+  return u;
+}
+
+template <typename Key, typename Value>
+inline message::unpacker& operator>>(message::unpacker& u,
+                                     std::pair<Key, Value>& v) {
+  message::unpacker sub;
+  u.iter_.recurse(sub.iter_);
+  sub >> v.first;
+  sub >> v.second;
+
+  u.iter_.next();
+  return u;
+}
+
 template <typename Element>
 inline message::unpacker& operator>>(message::unpacker& u,
                                      std::vector<Element>& s) {
-  static_assert(std::is_same<Element, std::string>::value,
-                "only std::vector<std::string> is implemented for now");
-  impl::message_iterator sub;
-  u.iter_.recurse(sub);
+  message::unpacker sub;
 
-  const char* c;
-  while (sub.has_next()) {
-    sub.get_basic(&c);
-    s.emplace_back(c);
-    sub.next();
-  }
-
-  // TODO(ed)
-  // Make this generic for all types.  The below code is close, but there's
-  // template issues and things I don't understand;
-  /*
-  auto e = message::unpacker(sub);
-  while (sub.has_next()) {
+  u.iter_.recurse(sub.iter_);
+  auto arg_type = sub.iter_.get_arg_type();
+  while (arg_type != DBUS_TYPE_INVALID) {
     s.emplace_back();
-    Element& element = s.back();
-    e.unpack(element);
+    sub >> s.back();
+    arg_type = sub.iter_.get_arg_type();
   }
-*/
+  u.iter_.next();
   return u;
 }
 
diff --git a/boost-dbus/test/avahi.cpp b/boost-dbus/test/avahi.cpp
index debbff3..8cbb82f 100644
--- a/boost-dbus/test/avahi.cpp
+++ b/boost-dbus/test/avahi.cpp
@@ -150,27 +150,114 @@
   }
 }
 
-TEST(BOOST_DBUS, ListObjects) {
+TEST(BOOST_DBUS, SingleSensorChanged) {
   boost::asio::io_service io;
   dbus::connection system_bus(io, dbus::bus::system);
 
-  dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
-                             "org.freedesktop.DBus");
+  dbus::match ma(system_bus,
+                 "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
+  dbus::filter f(system_bus, [](dbus::message& m) {
+    auto member = m.get_member();
+    return member == "PropertiesChanged";
+  });
 
-  // create new service browser
-  dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
-  auto r = system_bus.send(m);
+  // std::function<void(boost::system::error_code, dbus::message)> event_handler
+  // =
 
-  std::vector<std::string> services;
-  r.unpack(services);
-  // todo(ed) find out why this needs to be static
-  static std::atomic<int> dbus_count(0);
-  std::cout << dbus_count << " Callers\n";
-  auto names = std::make_shared<std::vector<std::string>>();
-  for (auto& service : services) {
-    std::string name = "/";
-    query_interfaces(system_bus, service, name);
-  }
+  f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
+    std::string object_name;
+    EXPECT_EQ(s.get_path(),
+              "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
+
+    std::vector<std::pair<std::string, dbus::dbus_variant>> values;
+    s.unpack(object_name).unpack(values);
+
+    EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
+
+    EXPECT_EQ(values.size(), 1);
+    auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
+    EXPECT_EQ(values[0], expected);
+
+    io.stop();
+  });
+
+  dbus::endpoint test_endpoint(
+      "org.freedesktop.Avahi",
+      "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+      "org.freedesktop.DBus.Properties");
+
+  auto signal_name = std::string("PropertiesChanged");
+  auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+  m.pack("xyz.openbmc_project.Sensor.Value");
+
+  std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
+
+  map2.emplace_back("Value", 42);
+
+  m.pack(map2);
+
+  auto removed = std::vector<uint32_t>();
+  m.pack(removed);
+  system_bus.async_send(m,
+                        [&](boost::system::error_code ec, dbus::message s) {});
 
   io.run();
 }
+
+TEST(BOOST_DBUS, MultipleSensorChanged) {
+  boost::asio::io_service io;
+  dbus::connection system_bus(io, dbus::bus::system);
+
+  dbus::match ma(system_bus,
+                 "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
+  dbus::filter f(system_bus, [](dbus::message& m) {
+    auto member = m.get_member();
+    return member == "PropertiesChanged";
+  });
+
+  int count = 0;
+  f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
+    std::string object_name;
+    EXPECT_EQ(s.get_path(),
+              "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
+
+    std::vector<std::pair<std::string, dbus::dbus_variant>> values;
+    s.unpack(object_name).unpack(values);
+
+    EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
+
+    EXPECT_EQ(values.size(), 1);
+    auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
+    EXPECT_EQ(values[0], expected);
+    count++;
+    if (count == 2) {
+      io.stop();
+    }
+
+  });
+
+  dbus::endpoint test_endpoint(
+      "org.freedesktop.Avahi",
+      "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+      "org.freedesktop.DBus.Properties");
+
+  auto signal_name = std::string("PropertiesChanged");
+  auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+  m.pack("xyz.openbmc_project.Sensor.Value");
+
+  std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
+
+  map2.emplace_back("Value", 42);
+
+  m.pack(map2);
+
+  auto removed = std::vector<uint32_t>();
+  m.pack(removed);
+  system_bus.async_send(m,
+                        [&](boost::system::error_code ec, dbus::message s) {});
+  system_bus.async_send(m,
+                        [&](boost::system::error_code ec, dbus::message s) {});
+  io.run();
+}
\ No newline at end of file
diff --git a/boost-dbus/test/message.cpp b/boost-dbus/test/message.cpp
index d591f61..8c8169f 100644
--- a/boost-dbus/test/message.cpp
+++ b/boost-dbus/test/message.cpp
@@ -3,9 +3,9 @@
 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-#include <dbus/error.hpp>
 #include <dbus/connection.hpp>
 #include <dbus/endpoint.hpp>
+#include <dbus/error.hpp>
 #include <dbus/filter.hpp>
 #include <dbus/match.hpp>
 #include <dbus/message.hpp>
@@ -35,6 +35,21 @@
   // m.get_sender();
 }
 
+TEST(MessageTest, Misc) {
+    auto signal_name = std::string("PropertiesChanged");
+  dbus::endpoint test_endpoint(
+      "org.freedesktop.Avahi",
+      "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+      "org.freedesktop.DBus.Properties");
+  auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+  dbus::dbus_variant v(std::string("hello world"));
+  m.pack(v);
+
+  std::vector<dbus::dbus_variant> av{{std::string("hello world"), 1, 42}};
+  m.pack(av);
+}
+
 // I actually don't know what to do with these yet.
 /*
 TEST(MessageTest, ErrorMessage)