system#

Description#

Plugin to get system info.

param thresholds:

A number, numeric pair or mapping of str to number/numeric pair representing the thresholds for the sensor.

Examples:

# Any value below 25 from any sensor will trigger a
# SensorDataBelowThresholdEvent, if the previous value was
# equal or above, and any value above 25 will trigger a
# SensorDataAboveThresholdEvent, if the previous value was
# equal or below
thresholds: 25.0

# Same as above, but the threshold is only applied to
# ``temperature`` readings
thresholds:
    temperature: 25.0

# Any value below 20 from any sensor will trigger a
# SensorDataBelowThresholdEvent, if the previous value was
# equal or above, and any value above 25 will trigger a
# SensorDataAboveThresholdEvent, if the previous value was
# equal or below (hysteresis configuration with double
# threshold)
thresholds:
    - 20.0
    - 25.0

# Same as above, but the threshold is only applied to
# ``temperature`` readings
thresholds:
    temperature:
        - 20.0
        - 25.0
Copy
param tolerance:

If set, then the sensor change events will be triggered only if the difference between the new value and the previous value is higher than the specified tolerance. For example, if the sensor data is mapped to a dictionary:

{
    "temperature": 0.01,  # Tolerance on the 2nd decimal digit
    "humidity": 0.1       # Tolerance on the 1st decimal digit
}
Copy

Or, if it’s a raw scalar number:

0.1  # Tolerance on the 1st decimal digit
Copy

Or, if it’s a list of values:

[
    0.01,   # Tolerance on the 2nd decimal digit for the first value
    0.1     # Tolerance on the 1st decimal digit for the second value
]
Copy
param enabled_sensors:

If SystemPlugin.get_measurement returns a key-value mapping, and enabled_sensors is set, then only the reported sensor keys will be returned.

Configuration#

system:
  # [Optional]
  # How often the `RunnablePlugin.loop <https://docs.platypush.tech/platypush/plugins/.html#platypush.plugins.RunnablePlugin.loop>`_ function should be
  # executed (default: 15 seconds). *NOTE*: For back-compatibility
  # reasons, the `poll_seconds` argument is also supported, but it's
  # deprecated.
  # poll_interval: 60  # type=Optional[float]

  # [Optional]
  # A number, numeric pair or mapping of ``str`` to
  # number/numeric pair representing the thresholds for the sensor.
  #
  # Examples:
  #
  #     .. code-block:: yaml
  #
  #         # Any value below 25 from any sensor will trigger a
  #         # SensorDataBelowThresholdEvent, if the previous value was
  #         # equal or above, and any value above 25 will trigger a
  #         # SensorDataAboveThresholdEvent, if the previous value was
  #         # equal or below
  #         thresholds: 25.0
  #
  #         # Same as above, but the threshold is only applied to
  #         # ``temperature`` readings
  #         thresholds:
  #             temperature: 25.0
  #
  #         # Any value below 20 from any sensor will trigger a
  #         # SensorDataBelowThresholdEvent, if the previous value was
  #         # equal or above, and any value above 25 will trigger a
  #         # SensorDataAboveThresholdEvent, if the previous value was
  #         # equal or below (hysteresis configuration with double
  #         # threshold)
  #         thresholds:
  #             - 20.0
  #             - 25.0
  #
  #         # Same as above, but the threshold is only applied to
  #         # ``temperature`` readings
  #         thresholds:
  #             temperature:
  #                 - 20.0
  #                 - 25.0
  # thresholds:   # type=Union[float, int, Tuple[Union[float, int], Union[float, int]], Mapping[str, Union[float, int, Tuple[Union[float, int], Union[float, int]]]], NoneType]

  # [Optional]
  # If set, then the sensor change events will be
  # triggered only if the difference between the new value and the
  # previous value is higher than the specified tolerance. For example,
  # if the sensor data is mapped to a dictionary::
  #
  #     {
  #         "temperature": 0.01,  # Tolerance on the 2nd decimal digit
  #         "humidity": 0.1       # Tolerance on the 1st decimal digit
  #     }
  #
  # Or, if it's a raw scalar number::
  #
  #     0.1  # Tolerance on the 1st decimal digit
  #
  # Or, if it's a list of values::
  #
  #     [
  #         0.01,   # Tolerance on the 2nd decimal digit for the first value
  #         0.1     # Tolerance on the 1st decimal digit for the second value
  #     ]
  # tolerance: 0  # type=Union[float, int, Mapping[str, Union[float, int]], Iterable[Union[float, int]]]

  # [Optional]
  # If `SensorPlugin.get_measurement <https://docs.platypush.tech/platypush/plugins/sensor.html#platypush.plugins.sensor.SensorPlugin.get_measurement>`_ returns a key-value
  # mapping, and ``enabled_sensors`` is set, then only the reported
  # sensor keys will be returned.
  # enabled_sensors:   # type=Optional[Iterable[str]]

  # [Optional]
  # How long we should wait for any running
  # threads/processes to stop before exiting (default: 5 seconds).
  # stop_timeout: 5  # type=Optional[float]

  # [Optional]
  # If set to True then the plugin will not monitor
  # for new events. This is useful if you want to run a plugin in
  # stateless mode and only leverage its actions, without triggering any
  # events. Defaults to False.
  # disable_monitor: False  # type=bool
Copy

Dependencies#

  • pip
  • Alpine
  • Debian
  • Fedora
  • Arch Linux
pip install py-cpuinfo psutil
CopyCopy

Actions#

Module reference#

class platypush.plugins.system.SystemPlugin(*_, **__)[source]#

Bases: SensorPlugin, EntityManager

Plugin to get system info.

__init__(*args, poll_interval: float | None = 60, **kwargs)[source]#
Parameters:
  • thresholds

    A number, numeric pair or mapping of str to number/numeric pair representing the thresholds for the sensor.

    Examples:

    # Any value below 25 from any sensor will trigger a
    # SensorDataBelowThresholdEvent, if the previous value was
    # equal or above, and any value above 25 will trigger a
    # SensorDataAboveThresholdEvent, if the previous value was
    # equal or below
    thresholds: 25.0
    
    # Same as above, but the threshold is only applied to
    # ``temperature`` readings
    thresholds:
        temperature: 25.0
    
    # Any value below 20 from any sensor will trigger a
    # SensorDataBelowThresholdEvent, if the previous value was
    # equal or above, and any value above 25 will trigger a
    # SensorDataAboveThresholdEvent, if the previous value was
    # equal or below (hysteresis configuration with double
    # threshold)
    thresholds:
        - 20.0
        - 25.0
    
    # Same as above, but the threshold is only applied to
    # ``temperature`` readings
    thresholds:
        temperature:
            - 20.0
            - 25.0
    Copy

  • tolerance

    If set, then the sensor change events will be triggered only if the difference between the new value and the previous value is higher than the specified tolerance. For example, if the sensor data is mapped to a dictionary:

    {
        "temperature": 0.01,  # Tolerance on the 2nd decimal digit
        "humidity": 0.1       # Tolerance on the 1st decimal digit
    }
    Copy

    Or, if it’s a raw scalar number:

    0.1  # Tolerance on the 1st decimal digit
    Copy

    Or, if it’s a list of values:

    [
        0.01,   # Tolerance on the 2nd decimal digit for the first value
        0.1     # Tolerance on the 1st decimal digit for the second value
    ]
    Copy

  • enabled_sensors – If get_measurement() returns a key-value mapping, and enabled_sensors is set, then only the reported sensor keys will be returned.

connected_users() List[dict][source]#

Get the list of connected users.

Returns:

{
  "pid": 1234,
  "started": "2021-01-01T00:00:00+00:00",
  "terminal": "tty1",
  "username": "johndoe"
}
Copy

cpu_frequency(per_cpu: bool = False) CpuFrequency | List[CpuFrequency][source]#

Get the CPU frequency, in MHz.

Parameters:

per_cpu – Get per-CPU stats (default: False).

Returns:

If per_cpu=False:

{
  "current": 2800000000.0,
  "max": 2800000000.0,
  "min": 800000000.0
}
Copy

If per_cpu=True then a list will be returned, where each item identifies the CPU times of a core:

[
  {
    "current": 2800000000.0,
    "max": 2800000000.0,
    "min": 800000000.0
  }
]
Copy
cpu_info()[source]#

Get CPU info. :return: .. schema:: system.CpuInfoSchema

cpu_percent(per_cpu: bool = False, interval: float | None = None) float | List[float][source]#

Get the CPU load percentage.

Parameters:
  • per_cpu – Get per-CPU stats (default: False).

  • interval – When interval is 0.0 or None compares system CPU times elapsed since last call or module import, returning immediately (non blocking). That means the first time this is called it will return a meaningless 0.0 value which you should ignore. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls.

Returns:

float if per_cpu=False, list[float] otherwise.

cpu_stats() CpuStats[source]#

Get CPU stats.

Returns:

{
  "ctx_switches": 1234,
  "interrupts": 1234,
  "soft_interrupts": 1234,
  "syscalls": 1234
}
Copy

cpu_times(per_cpu=False, percent=True) list | dict[source]#

Get the CPU times per status, either as absolute time or a percentage.

Parameters:
  • per_cpu – Get per-CPU stats (default: False).

  • percent – Get the stats in percentage (default: True).

Returns:

If per_cpu=False:

{
  "guest": 37,
  "guest_nice": 66,
  "idle": 11,
  "iowait": 93,
  "irq": 17,
  "nice": 81,
  "softirq": 4,
  "steal": 18,
  "system": 67,
  "user": 78
}
Copy

If per_cpu=True then a list will be returned, where each item identifies the CPU times of a core:

[
  {
    "guest": 3,
    "guest_nice": 83,
    "idle": 84,
    "iowait": 61,
    "irq": 9,
    "nice": 63,
    "softirq": 19,
    "steal": 49,
    "system": 8,
    "user": 8
  }
]
Copy
disk_info()[source]#

Get information about the detected disks and partitions.

Returns:

[
  {
    "busy_time": 20.5,
    "device": "/dev/sda1",
    "free": 1072693248,
    "fstype": "ext4",
    "mountpoint": "/mnt/data",
    "opts": "rw,relatime",
    "percent": 86,
    "read_bytes": 1073741824,
    "read_count": 100,
    "read_time": 10.5,
    "total": 1073741824,
    "used": 1048576,
    "write_bytes": 1048576,
    "write_count": 50,
    "write_time": 5.5
  }
]
Copy

get_data(*args, **kwargs)#

(Deprecated) alias for get_measurement()

get_measurement(*_, **__)[source]#
Returns:

{
  "battery": {
    "power_plugged": "Whether the battery is currently plugged in",
    "seconds_left": 7200,
    "value": 70
  },
  "cpu": {
    "frequency": {
      "current": 2800000000.0,
      "max": 2800000000.0,
      "min": 800000000.0
    },
    "info": {
      "architecture": "x86_64",
      "bits": 64,
      "brand": "Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz",
      "cores": 4,
      "flags": [
        "fpu",
        "vme",
        "de",
        "pse",
        "tsc",
        "msr",
        "pae"
      ],
      "frequency_actual": 2650000000.0,
      "frequency_advertised": 2800000000.0,
      "l1_data_cache_size": 65536,
      "l1_instruction_cache_size": 65536,
      "l2_cache_size": 524288,
      "l3_cache_size": 6291456,
      "vendor": "GenuineIntel"
    },
    "load_avg": [
      0.0,
      0.0,
      0.0
    ],
    "percent": 90,
    "stats": {
      "ctx_switches": 1234,
      "interrupts": 1234,
      "soft_interrupts": 1234,
      "syscalls": 1234
    },
    "times": {
      "guest": 75,
      "guest_nice": 90,
      "idle": 19,
      "iowait": 76,
      "irq": 1,
      "nice": 33,
      "softirq": 28,
      "steal": 33,
      "system": 88,
      "user": 91
    }
  },
  "disks": [
    {
      "busy_time": 20.5,
      "device": "/dev/sda1",
      "free": 1072693248,
      "fstype": "ext4",
      "mountpoint": "/mnt/data",
      "opts": "rw,relatime",
      "percent": 1,
      "read_bytes": 1073741824,
      "read_count": 100,
      "read_time": 10.5,
      "total": 1073741824,
      "used": 1048576,
      "write_bytes": 1048576,
      "write_count": 50,
      "write_time": 5.5
    }
  ],
  "fans": [
    {
      "id": "acpi_1",
      "label": "CPU Fan",
      "value": 1200
    }
  ],
  "memory": {
    "active": 4294967296,
    "available": 2147483648,
    "buffers": 2147483648,
    "cached": 2147483648,
    "free": 2147483648,
    "inactive": 2147483648,
    "percent": 30,
    "shared": 3221225472,
    "total": 8589934592,
    "used": 6442450944
  },
  "network": [
    {
      "addresses": [
        {
          "address": "192.168.1.4",
          "broadcast": "192.168.1.255",
          "family": "AF_INET",
          "netmask": "255.255.255.0"
        }
      ],
      "bytes_recv": 654321,
      "bytes_sent": 123456,
      "drop_in": 1,
      "drop_out": 2,
      "duplex": "FULL",
      "errors_in": 10,
      "errors_out": 5,
      "flags": [
        "up",
        "broadcast",
        "running",
        "multicast"
      ],
      "interface": "eth0",
      "is_up": true,
      "mtu": 1500,
      "packets_recv": 321,
      "packets_sent": 123,
      "speed": 1000
    }
  ],
  "swap": {
    "free": 2147483648,
    "percent": 45,
    "total": 8589934592,
    "used": 6442450944
  },
  "temperature": [
    {
      "critical": 100.0,
      "high": 90.0,
      "id": "acpi_1",
      "label": "CPU Temperature",
      "value": 56.0
    }
  ]
}
Copy

kill(pid: int)[source]#

Kill a process. :param pid: Process PID.

load_avg() Tuple[float, float, float][source]#

Get the average load as a vector that represents the load within the last 1, 5 and 15 minutes.

mem_swap() dict[source]#

Get the current swap memory usage stats.

Returns:

{
  "free": 2147483648,
  "percent": 45,
  "total": 8589934592,
  "used": 6442450944
}
Copy

mem_virtual() dict[source]#

Get the current virtual memory usage stats.

Returns:

{
  "active": 4294967296,
  "available": 2147483648,
  "buffers": 2147483648,
  "cached": 2147483648,
  "free": 2147483648,
  "inactive": 2147483648,
  "percent": 52,
  "shared": 3221225472,
  "total": 8589934592,
  "used": 6442450944
}
Copy

network_connections(type: str = 'inet') List[dict][source]#

Get the list of active network connections. On MacOS this function requires root privileges.

Parameters:

type

Connection type to filter (default: inet). Supported types:

type

Description

inet inet4 inet6 tcp tcp4 tcp6 udp udp4 udp6 unix all

IPv4 and IPv6 IPv4 IPv6 TCP TCP over IPv4 TCP over IPv6 UDP UDP over IPv4 UDP over IPv6 UNIX socket (both UDP and TCP protocols) Any families and protocols

Returns:

[
  {
    "family": "AF_INET",
    "fd": 3,
    "local_address": "192.168.1.3",
    "local_port": 1234,
    "pid": 1234,
    "remote_address": "192.168.1.4",
    "remote_port": 5678,
    "status": "ESTABLISHED",
    "type": "SOCK_STREAM"
  }
]
Copy

network_info(per_nic: bool = False)[source]#

Get the information and statistics for the network interfaces.

Parameters:

per_nic – Return the stats grouped by interface (default: False).

Returns:

If per_nic=False:

{
  "addresses": [
    {
      "address": "192.168.1.4",
      "broadcast": "192.168.1.255",
      "family": "AF_INET",
      "netmask": "255.255.255.0"
    }
  ],
  "bytes_recv": 654321,
  "bytes_sent": 123456,
  "drop_in": 1,
  "drop_out": 2,
  "duplex": "FULL",
  "errors_in": 10,
  "errors_out": 5,
  "flags": [
    "up",
    "broadcast",
    "running",
    "multicast"
  ],
  "interface": "eth0",
  "is_up": true,
  "mtu": 1500,
  "packets_recv": 321,
  "packets_sent": 123,
  "speed": 1000
}
Copy

If per_nic=True then a list will be returned, where each item identifies the statistics per network interface:

[
  {
    "addresses": [
      {
        "address": "192.168.1.4",
        "broadcast": "192.168.1.255",
        "family": "AF_INET",
        "netmask": "255.255.255.0"
      }
    ],
    "bytes_recv": 654321,
    "bytes_sent": 123456,
    "drop_in": 1,
    "drop_out": 2,
    "duplex": "FULL",
    "errors_in": 10,
    "errors_out": 5,
    "flags": [
      "up",
      "broadcast",
      "running",
      "multicast"
    ],
    "interface": "eth0",
    "is_up": true,
    "mtu": 1500,
    "packets_recv": 321,
    "packets_sent": 123,
    "speed": 1000
  }
]
Copy
pid_exists(pid: int) bool[source]#
Parameters:

pid – Process PID.

Returns:

True if the process exists, False otherwise.

processes() List[dict][source]#

Get the list of running processes.

Returns:

{
  "command_line": [
    "python",
    "script.py"
  ],
  "cpu_percent": 63,
  "current_directory": "/home/user",
  "memory_percent": 73,
  "name": "python",
  "parent_pid": 1000,
  "pid": 1234,
  "started": "2021-01-01T00:00:00+00:00",
  "status": "running",
  "terminal": "tty1",
  "username": "root"
}
Copy

publish_entities(entities: float | int | Mapping[str, float | int] | Iterable[float | int], *args, **kwargs) Collection[Entity]#

Publishes a list of entities. The downstream consumers include:

It also accepts an optional callback that will be called when each of the entities in the set is flushed to the database.

You usually don’t need to override this class (but you may want to extend transform_entities() instead if your extension doesn’t natively handle Entity objects).

resume(pid: int)[source]#

Resume a process. :param pid: Process PID.

sensors_battery() dict | None[source]#

Get stats from the battery sensor.

Returns:

{
  "power_plugged": "Whether the battery is currently plugged in",
  "seconds_left": 7200,
  "value": 81
}
Copy

sensors_fan() List[dict][source]#

Get stats from the fan sensors.

Returns:

[
  {
    "id": "acpi_1",
    "label": "CPU Fan",
    "value": 1200
  }
]
Copy

sensors_temperature() List[dict][source]#

Get stats from the temperature sensors.

Returns:

[
  {
    "critical": 100.0,
    "high": 90.0,
    "id": "acpi_1",
    "label": "CPU Temperature",
    "value": 56.0
  }
]
Copy

status(*_, **__) float | int | Mapping[str, float | int] | Iterable[float | int] | None#

Returns the latest read values and publishes the platypush.message.event.entities.EntityUpdateEvent events if required.

suspend(pid: int)[source]#

Suspend a process. :param pid: Process PID.

terminate(pid: int)[source]#

Terminate a process. :param pid: Process PID.

transform_entities(entities: dict) List[Entity][source]#

This method takes a list of entities in any (plugin-specific) format and converts them into a standardized collection of Entity objects. Since this method is called by publish_entities() before entity updates are published, you may usually want to extend it to pre-process the entities managed by your extension into the standard format before they are stored and published to all the consumers.

wait(pid: int, timeout: int | None = None)[source]#

Wait for a process to terminate.

Parameters:
  • pid – Process PID.

  • timeout – Timeout in seconds (default: None).