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
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
}

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
]
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

Dependencies#

pip

pip install psutil py-cpuinfo

Alpine

apk add py3-psutil py3-py-cpuinfo

Debian

apt install python3-psutil python3-cpuinfo

Fedora

yum install python-cpuinfo python-psutil

Arch Linux

pacman -S python-py-cpuinfo python-psutil

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
    

  • 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
    }
    

    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
    ]
    

  • 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"
}

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
}

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
  }
]
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
}

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": 17,
  "guest_nice": 84,
  "idle": 68,
  "iowait": 89,
  "irq": 16,
  "nice": 91,
  "softirq": 13,
  "steal": 93,
  "system": 42,
  "user": 20
}

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

[
  {
    "guest": 9,
    "guest_nice": 46,
    "idle": 93,
    "iowait": 74,
    "irq": 56,
    "nice": 55,
    "softirq": 39,
    "steal": 78,
    "system": 51,
    "user": 8
  }
]
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": 85,
    "read_bytes": 1073741824,
    "read_count": 100,
    "read_time": 10.5,
    "total": 1073741824,
    "used": 1048576,
    "write_bytes": 1048576,
    "write_count": 50,
    "write_time": 5.5
  }
]

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": 87
  },
  "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": 96,
    "stats": {
      "ctx_switches": 1234,
      "interrupts": 1234,
      "soft_interrupts": 1234,
      "syscalls": 1234
    },
    "times": {
      "guest": 70,
      "guest_nice": 80,
      "idle": 27,
      "iowait": 84,
      "irq": 66,
      "nice": 36,
      "softirq": 50,
      "steal": 91,
      "system": 19,
      "user": 79
    }
  },
  "disks": [
    {
      "busy_time": 20.5,
      "device": "/dev/sda1",
      "free": 1072693248,
      "fstype": "ext4",
      "mountpoint": "/mnt/data",
      "opts": "rw,relatime",
      "percent": 56,
      "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": 84,
    "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": 84,
    "total": 8589934592,
    "used": 6442450944
  },
  "temperature": [
    {
      "critical": 100.0,
      "high": 90.0,
      "id": "acpi_1",
      "label": "CPU Temperature",
      "value": 56.0
    }
  ]
}

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.

main()#

Implementation of the main loop of the plugin.

mem_swap() dict[source]#

Get the current swap memory usage stats.

Returns:

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

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": 31,
  "shared": 3221225472,
  "total": 8589934592,
  "used": 6442450944
}

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"
  }
]

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
}

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
  }
]
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": 85,
  "current_directory": "/home/user",
  "memory_percent": 96,
  "name": "python",
  "parent_pid": 1000,
  "pid": 1234,
  "started": "2021-01-01T00:00:00+00:00",
  "status": "running",
  "terminal": "tty1",
  "username": "root"
}

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": 48
}

sensors_fan() List[dict][source]#

Get stats from the fan sensors.

Returns:

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

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
  }
]

start()#

Start the plugin.

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.

stop()#

Stop the plugin.

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).

wait_stop(timeout=None)#

Wait until a stop event is received.