Skip to main content
Heex provides a Monitor class that will be instantiated in your implementations to monitor the dataflow of your edge system. The Monitor class is a generic class that can be used to monitor several types of dataflows like boolean, string, float, integers, geographic, etc. Do you happen to have a use case that is not covered by our ready-to-use classes ? Don’t worry, just contact us at contact@heex.io and we will work with you to provide a custom class.

Monitor Build

To integrate monitors and recorders in your project you have to build with Heex libraries. See HeexSDK integration for details.

Monitor main APIs

Monitor(id, serverIp, serverPort)
  • Id : Monitor implementation ID, that can be retrieved on the Heex Cloud
  • serverIp : IP address to contact Heex Kernel
  • serverPort : Port to contact Heex Kernel
awaitReady() : To wait until the monitor is ready to receive data. Please ensure this function returns True before continuing. getMonitorSignals(triggerId="", signalName="") : Returns all the MonitoringSignal your monitor is monitoring. triggerId and signalName can be left empty or filled if you want to filter specific signals. setConditionState(state, signalName, timestamp="") : Set the state of given monitoring signal condition. This allows to trigger the condition state of any monitoring condition of a signal. NOTE: currently we only support this method for CUSTOM signals. sendMessageToImplementation(messages, destinationImplementationId="") : All implementations can communicate with each other. To send a message, use this method by filling in the const std::vector<std::string>& messages as you please, and specify the destination implementation ID. You may leave this last one empty, and if so, it’ll broadcast to all other connected implementations. handleMessageFromOtherImplementation(sourceImplementationId, messages) : All implementations can communicate with each other. When a message is received, this callback is called. It is up to you to overload this method and decide what to do with the messages. updateValue(inputValue) : To update the in-memory value of your signal, and communicate with the Heex Kernel when the conditions set on the Heex Cloud are met. updateValue(inputValue, timestamp="") : Call updateValue with the timestamp in the form of a string. updateValueBySignalName(inputValue, timestamp="", signalName="") : Call updateValue but only for the signal with the specified name. Timestamp can be set to "" if you want us to set the timestamp at local time. These updateValue and updateValueBySignalName APIs are template functions, so you can use them with any type of dataflow, in particular:
  • bool : boolean dataflow
  • int, uint, short, long : integer dataflow
  • float, double : float dataflow
  • string, char* : string dataflow
  • HeexGps : geographic dataflow (see below)

HeexGps structure

// @brief Structure to get GPS informations.
///
/// @param lat The latitude coordinate
/// @param lon The longitude coordinate
struct HeexGps
{
  double lat{0.0}; ///< The latitude coordinate
  double lon{0.0}; ///< The longitude coordinate

  /// @brief Default constructor
  HeexGps() = default;

  /// @brief Constructor with latitude and longitude
  /// @param latIn The latitude coordinate
  /// @param lonIn The longitude coordinate
  HeexGps(const double& latIn, const double& lonIn) : lat{latIn}, lon{lonIn} {};

  /// @brief Copy constructor
  HeexGps(const HeexGps& other) = default;

  /// @brief Copy assignment operator
  HeexGps& operator=(const HeexGps& other) = default;

  /// @brief Move assignment operator
  HeexGps& operator=(HeexGps&& other) = default;

  /// @brief Equality comparison operator
  /// @param other The other HeexGps to compare with
  /// @return true if both latitude and longitude are equal, false otherwise
  bool operator==(const HeexGps& other) const { return lat == other.lat && lon == other.lon; }

  /// @brief Inequality comparison operator
  /// @param other The other HeexGps to compare with
  /// @return true if latitude or longitude are different, false otherwise
  bool operator!=(const HeexGps& other) const { return !(*this == other); }
};

MonitoringSignal structure

/// @brief Structure to hold a monitoring signal
///
/// @param id The ID of the signal.
/// @param name The name of the signal. For ROS topics, the format is '/topicName>subtopic1>subtopic...'. eg: '/imu>angular_velocity>x'
/// @param unit The unit of the signal. enum value (eg: 1 -> METER_PER_SECOND, 2 -> METER, 3 -> KILOMETER, etc.)
/// @param rosTopicType The ROS topic type of the signal. Only used for ROS topics, eg 'sensor_msgs/msg/NavSatFix'
/// @param datasourceId The ID of the datasource this signal is associated to.
/// @param datasourceName The name of the datasource this signal is associated to.
/// @param signalType The type of the signal. enum value (eg: 1 -> INTEGER, 2 -> NUMBER, 7 -> STRING, 6 -> BOOLEAN...)
/// @param signalOperator The operator of the signal. enum value (eg: 1 -> IN, 2 -> OUT, 10 -> LESS_THAN, etc.)
/// @param valueType The type of the  monitored value. (eg: "double", "string", "bool", "array", "zone"...)
/// @param value The stringified triggering value. (eg: "1.23", "true", "['a', 'b', 'c']", "some text", "zone"...)

struct MonitoringSignal
{
  std::string id{};   ///< The ID of the signal.
  std::string name{}; ///< The name of the signal. For ROS topics, the format is '/topicName>subtopic1>subtopic...'. eg: '/imu>angular_velocity>x'
  int unit{static_cast<int>(apiinterface::Unit::UNIT_UNSPECIFIED)};           ///< The unit of the signal. enum value (eg: 1 -> METER_PER_SECOND, 2 -> METER, 3 -> KILOMETER, etc.)
  std::string rosTopicType{};                                                 ///< The ROS topic type of the signal. Only used for ROS topics, eg 'sensor_msgs/msg/NavSatFix'
  std::string datasourceId{};                                                 ///< The ID of the datasource this signal is associated to.
  std::string datasourceName{};                                               ///< The name of the datasource this signal is associated to.
  std::string conditionId{};                                                  ///< The ID of the monitoring signal condition this signal is associated to.
  int signalType{static_cast<int>(apiinterface::SignalType::ST_UNSPECIFIED)}; ///< The type of the signal enum value (eg: 1 -> INTEGER, 2 -> NUMBER, 7 -> STRING, 6 -> BOOLEAN...)
  int signalOperator{static_cast<int>(apiinterface::Operator::OP_UNSPECIFIED)}; ///< The operator of the signal enum value (eg: 1 -> IN, 2 -> OUT, 10 -> LESS_THAN, etc.)
  std::string valueType{};                                                      ///< The type of the  monitored value. (eg: "double", "string", "bool", "array", "zone"...)
  std::string value{}; ///< The stringified triggering value. (eg: "1.23", "true", "['a', 'b', 'c']", "some text", "zone"...)

  /// @brief Copy assignment operator
  /// @param other The other MonitoringSignal to copy from
  /// @return Reference to this MonitoringSignal
  MonitoringSignal& operator=(const MonitoringSignal& other) = default;

  /// @brief Equality comparison operator
  /// @param other The other MonitoringSignal to compare with
  /// @return true if all fields are equal, false otherwise
  bool operator==(const MonitoringSignal& other) const
  {
    return (
        id == other.id && name == other.name && unit == other.unit && rosTopicType == other.rosTopicType && datasourceId == other.datasourceId &&
        datasourceName == other.datasourceName && conditionId == other.conditionId && signalType == other.signalType && signalOperator == other.signalOperator &&
        valueType == other.valueType && value == other.value);
  }

  /// @brief Convert the unit to a stringified enum value for human readability (ie: 0 -> UNIT_UNSPECIFIED, 1 -> METER_PER_SECOND, etc.)
  /// @return the stringified enum value
  std::string unitToString() const
  {
    auto u = static_cast<apiinterface::Unit>(unit);
    return apiinterface::Unit_Name(u);
  }

  /// @brief Convert the signal type to a stringified enum value for human readability (ie: 0 -> ST_UNSPECIFIED, 1 -> INTEGER, etc.)
  /// @return the stringified enum value
  std::string signalTypeToString() const
  {
    auto t = static_cast<apiinterface::SignalType>(signalType);
    return apiinterface::SignalType_Name(t);
  }

  /// @brief Convert the signal operator to a stringified enum value for human readability (ie: 0 -> OP_UNSPECIFIED, 1 -> IN, 2 -> OUT, etc.)
  /// @return the stringified enum value
  std::string signalOperatorToString() const
  {
    auto o = static_cast<apiinterface::Operator>(signalOperator);
    return apiinterface::Operator_Name(o);
  }
};

Monitor implementation

Let’s write a small example. The Monitor can monitor a speed dataflow in a range.
  • C++
  • Python
You have to include Monitor.hThen, instantiation is done calling the constructor:
Monitor myMonitor("m-1a7453c0-ef64-4290-a9c3-5019e8bb43fa", "127.0.0.1", 4242);
if (myMonitor.awaitReady() == false) // awaits the connection with the kernel.
{
  return EXIT_FAILURE;
}
Using the awaitReady() allows to wait until your monitor establishes a connection with the Heex Kernel. The monitor will detect events based on the values that are sent to it, so you should call updateValue() method with the value of your signal. It could be at regular time intervals or when the signal changes. This is highly dependant to your edge system. To do that, use the following code:
my_monitor.updateValue(speed);
🎉 CONGRATULATIONS! This is it!
You don’t need to care about the bounds set in the Heex Cloud when specifying the trigger. All the checking will occur behind the scene and the Heex Agent will take care of detecting when matching conditions are met to trigger events.
ℹ️ Info: timestamp It is recommended to call UpdateValue method, giving as second argument the exact timestamp of your signal value formatted in ISO 8601-1:2019. Otherwise the current system time is applied by default to your signal value.
For more information go to Timestamp Formatting page.

Monitor Samples

You can check the samples here.