diff --git a/src/action.rs b/src/action.rs
index 868a093467afbb541e5b68b3ae0bc861ce6fd09f..840561cf88ea6d2ae3a6d7279855d0fa7000f167 100644
--- a/src/action.rs
+++ b/src/action.rs
@@ -63,11 +63,7 @@ impl Action {
                 }?;
 
                 let maybe_device = match device_identifier {
-                    Some(device_identifier) => {
-                        let identifier = device_identifier.into_device(conn).await?;
-
-                        Some(identifier)
-                    }
+                    Some(device_identifier) => device_identifier.into_device(conn).await?,
                     None => None,
                 };
 
diff --git a/src/condition.rs b/src/condition.rs
index ff1492847412ec2c20b383824f919283296c6882..ec7f3693fc5a7a41ee96b7f9161a322d237eecc7 100644
--- a/src/condition.rs
+++ b/src/condition.rs
@@ -2,13 +2,13 @@ use std::{collections::HashSet, sync::Arc};
 
 use anyhow::Result;
 use dbus::nonblock::SyncConnection;
-use futures::{future::join_all, stream, StreamExt};
+use futures::{stream, StreamExt};
 use serde_derive::{Deserialize, Serialize};
 
 use crate::{
     dbus_wrappers::{
-        active_connection::ActiveConnectionWrapper, device::DeviceWrapper,
-        device_state::DeviceState,
+        active_connection::ActiveConnectionWrapper, connectivity_state::ConnectivityState,
+        device::DeviceWrapper, device_state::DeviceState, manager::ManagerWrapper, state::State,
     },
     identifier::{ActiveConnectionIdentifier, DeviceIdentifier},
 };
@@ -20,6 +20,10 @@ pub enum Condition {
     AlwaysTrue,
     // Always fails.
     AlwaysFalse,
+    // Passes if the last connectivity check is any of the specificed states.
+    ConnectivityStateIsAnyOf {
+        states: HashSet<ConnectivityState>,
+    },
     // Passes if the device has any active connections.
     DeviceIsConnected {
         device_identifier: DeviceIdentifier,
@@ -53,6 +57,11 @@ pub enum Condition {
     //     device_identifier: DeviceIdentifier,
     //     ssids: Vec<String>,
     // },
+    // Passes if the current NetworkManager state is one of the specified
+    // states.
+    StateIsAnyOf {
+        states: HashSet<State>,
+    },
 }
 
 impl Condition {
@@ -60,15 +69,28 @@ impl Condition {
         match self {
             Condition::AlwaysTrue => Ok(true),
             Condition::AlwaysFalse => Ok(false),
+            Condition::ConnectivityStateIsAnyOf { states } => {
+                log::debug!("Evaluating ConnectivityStateIsAnyOf condition");
+
+                let manager = ManagerWrapper::from_connection(conn).await;
+
+                Ok(states.contains(&manager.get_last_connectivity_state().await?))
+            }
             Condition::DeviceIsConnected {
                 device_identifier: device_id,
             } => {
                 log::debug!("Evaluating DeviceIsConnected condition for {:?}", device_id);
 
-                let device = device_id.into_device(conn).await?;
-
-                device_matches_states(&device, vec![DeviceState::Activated].into_iter().collect())
-                    .await
+                match device_id.into_device(conn).await? {
+                    Some(device) => {
+                        device_matches_states(
+                            &device,
+                            vec![DeviceState::Activated].into_iter().collect(),
+                        )
+                        .await
+                    }
+                    None => Ok(false),
+                }
             }
             Condition::DeviceIsNotConnected {
                 device_identifier: device_id,
@@ -78,15 +100,18 @@ impl Condition {
                     device_id
                 );
 
-                let device = device_id.into_device(conn).await?;
-
-                device_matches_states(
-                    &device,
-                    vec![DeviceState::Disconnected, DeviceState::Unavailable]
-                        .into_iter()
-                        .collect(),
-                )
-                .await
+                match device_id.into_device(conn).await? {
+                    Some(device) => {
+                        device_matches_states(
+                            &device,
+                            vec![DeviceState::Disconnected, DeviceState::Unavailable]
+                                .into_iter()
+                                .collect(),
+                        )
+                        .await
+                    }
+                    None => Ok(true),
+                }
             }
             Condition::DeviceStateIsAnyOf {
                 device_identifier: device_id,
@@ -97,9 +122,10 @@ impl Condition {
                     device_id
                 );
 
-                let device = device_id.into_device(conn).await?;
-
-                device_matches_states(&device, states.clone()).await
+                match device_id.into_device(conn).await? {
+                    Some(device) => device_matches_states(&device, states.clone()).await,
+                    None => Ok(false),
+                }
             }
             Condition::DeviceIsConnectedToOneOf {
                 device_identifier: device_id,
@@ -123,7 +149,13 @@ impl Condition {
 
                 Ok(!device_is_connected_to_one_of(conn, device_id, connections).await?)
             }
-            _ => Ok(false),
+            Condition::StateIsAnyOf { states } => {
+                log::debug!("Evaluating StateIsAnyOf condition");
+
+                let manager = ManagerWrapper::from_connection(conn).await;
+
+                Ok(states.contains(&manager.get_state().await?))
+            }
         }
     }
 }
@@ -143,46 +175,49 @@ async fn device_is_connected_to_one_of<'a>(
     device_identifier: &DeviceIdentifier,
     connections: &'a Vec<ActiveConnectionIdentifier>,
 ) -> Result<bool> {
-    let device = device_identifier.into_device(conn).await?;
-
-    let active_connections: Vec<ActiveConnectionWrapper<'a>> = stream::iter(connections)
-        .filter_map(|connection_identifier| async move {
-            match connection_identifier.into_active_connection(conn).await {
-                Ok(active_connection) => active_connection,
-                Err(err) => {
-                    log::error!(
-                        "Got error retrieving active connection for {:?}: {:?}",
-                        connection_identifier,
-                        err
-                    );
-
-                    None
-                }
-            }
-        })
-        .collect()
-        .await;
-
-    let has_any_matches = stream::iter(active_connections).any(|active_connection| {
-        let device_path = device.get_path();
-
-        async move {
-            let device_paths = active_connection.get_device_paths().await;
-
-            match device_paths {
-                Ok(device_paths) => device_paths.iter().any(|x| x.eq(&device_path)),
-                Err(err) => {
-                    log::error!(
-                        "Unable to get device paths for active connection {:?}: {:?}",
-                        active_connection.get_path(),
-                        err
-                    );
-
-                    false
+    match device_identifier.into_device(conn).await? {
+        Some(device) => {
+            let active_connections: Vec<ActiveConnectionWrapper<'a>> = stream::iter(connections)
+                .filter_map(|connection_identifier| async move {
+                    match connection_identifier.into_active_connection(conn).await {
+                        Ok(active_connection) => active_connection,
+                        Err(err) => {
+                            log::error!(
+                                "Got error retrieving active connection for {:?}: {:?}",
+                                connection_identifier,
+                                err
+                            );
+
+                            None
+                        }
+                    }
+                })
+                .collect()
+                .await;
+
+            let has_any_matches = stream::iter(active_connections).any(|active_connection| {
+                let device_path = device.get_path();
+
+                async move {
+                    let device_paths = active_connection.get_device_paths().await;
+
+                    match device_paths {
+                        Ok(device_paths) => device_paths.iter().any(|x| x.eq(&device_path)),
+                        Err(err) => {
+                            log::error!(
+                                "Unable to get device paths for active connection {:?}: {:?}",
+                                active_connection.get_path(),
+                                err
+                            );
+
+                            false
+                        }
+                    }
                 }
-            }
-        }
-    });
+            });
 
-    Ok(has_any_matches.await)
+            Ok(has_any_matches.await)
+        }
+        None => Ok(false),
+    }
 }
diff --git a/src/dbus_wrappers/connection.rs b/src/dbus_wrappers/connection.rs
index f56cea4641715c4cec9315cc68041506118b30a9..1b83b3b7cf366c898b5dd722d3ef4e37e42aa75f 100644
--- a/src/dbus_wrappers/connection.rs
+++ b/src/dbus_wrappers/connection.rs
@@ -1,11 +1,8 @@
 use std::{sync::Arc, time::Duration};
 
-use anyhow::Result;
 use dbus::{Path, nonblock::{Proxy, SyncConnection}};
 
-use crate::dbus_codegen::{network_manager_connection_active::{OrgFreedesktopNetworkManagerConnectionActive, OrgFreedesktopNetworkManagerConnectionActiveStateChanged}};
-
-use super::signal::SignalStreamWrapper;
+use crate::dbus_codegen::{network_manager_connection_active::{OrgFreedesktopNetworkManagerConnectionActive}};
 
 pub struct ConnectionWrapper<'a> {
     conn: Arc<SyncConnection>,
diff --git a/src/dbus_wrappers/connectivity_state.rs b/src/dbus_wrappers/connectivity_state.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cce00a67c7f675e2a4bbb0cf9eebc07081a077d7
--- /dev/null
+++ b/src/dbus_wrappers/connectivity_state.rs
@@ -0,0 +1,13 @@
+use num_derive::FromPrimitive;
+use serde_derive::{Deserialize, Serialize};
+
+// NMConnectivityState
+#[derive(FromPrimitive, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Debug)]
+#[repr(u32)]
+pub enum ConnectivityState {
+    Unknown = 0,
+    None = 1,
+    Portal = 2,
+    Limited = 3,
+    Full = 4,
+}
\ No newline at end of file
diff --git a/src/dbus_wrappers/device.rs b/src/dbus_wrappers/device.rs
index 84579d7692a7d18031f3ae5969299919212bc034..43a2b8aed8eedf1752e7a78d8d8dfc86e0dd33c9 100644
--- a/src/dbus_wrappers/device.rs
+++ b/src/dbus_wrappers/device.rs
@@ -1,4 +1,4 @@
-use std::{convert::TryFrom, sync::Arc, time::Duration};
+use std::{sync::Arc, time::Duration};
 
 use anyhow::Result;
 use dbus::{
diff --git a/src/dbus_wrappers/manager.rs b/src/dbus_wrappers/manager.rs
index c45872a206befff0adc95414f3d7d79dc88776a6..05dcee96d0d44a6cc510ea07ef556bb48b685f12 100644
--- a/src/dbus_wrappers/manager.rs
+++ b/src/dbus_wrappers/manager.rs
@@ -1,20 +1,21 @@
 use std::{sync::Arc, time::Duration};
 
+use anyhow::Result;
 use dbus::{
-    nonblock::{Proxy, SyncConnection},
+    nonblock::{stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged, Proxy, SyncConnection},
     Path,
 };
 use futures::{future::join_all, stream, StreamExt};
+use num_traits::FromPrimitive;
 
 use crate::dbus_codegen::network_manager::{
     OrgFreedesktopNetworkManager, OrgFreedesktopNetworkManagerDeviceAdded,
     OrgFreedesktopNetworkManagerDeviceRemoved,
 };
 
-use super::{
-    active_connection::ActiveConnectionWrapper, connection::ConnectionWrapper,
-    device::DeviceWrapper, signal::SignalStreamWrapper,
-};
+use super::{active_connection::ActiveConnectionWrapper, connection::ConnectionWrapper, connectivity_state::ConnectivityState, device::DeviceWrapper, signal::SignalStreamWrapper, state::State};
+
+const PATH: &'static str = "/org/freedesktop/NetworkManager";
 
 pub struct ManagerWrapper<'a> {
     conn: Arc<SyncConnection>,
@@ -27,7 +28,7 @@ impl<'a> ManagerWrapper<'a> {
 
         let proxy: Proxy<'a, Arc<SyncConnection>> = Proxy::new(
             "org.freedesktop.NetworkManager",
-            "/org/freedesktop/NetworkManager",
+            PATH,
             Duration::from_millis(5000),
             inner_conn,
         );
@@ -102,6 +103,16 @@ impl<'a> ManagerWrapper<'a> {
         Ok(matches.pop())
     }
 
+    pub async fn get_state(&self) -> Result<State> {
+        Ok(FromPrimitive::from_u32(self.inner.state().await?)
+            .unwrap_or(State::Unknown))
+    }
+
+    pub async fn get_last_connectivity_state(&self) -> Result<ConnectivityState> {
+        Ok(FromPrimitive::from_u32(self.inner.connectivity().await?)
+            .unwrap_or(ConnectivityState::Unknown))
+    }
+
     pub async fn activate_connection(
         &self,
         connection: Option<&'a ConnectionWrapper<'a>>,
@@ -145,4 +156,10 @@ impl<'a> ManagerWrapper<'a> {
     ) -> anyhow::Result<SignalStreamWrapper<OrgFreedesktopNetworkManagerDeviceRemoved>> {
         SignalStreamWrapper::from_match_rule(&self.conn, None, None).await
     }
+
+    pub async fn properties_changed_signal_stream(
+        &self,
+    ) -> anyhow::Result<SignalStreamWrapper<PropertiesPropertiesChanged>> {
+        SignalStreamWrapper::from_match_rule(&self.conn, None, Some(Path::from(PATH))).await
+    }
 }
diff --git a/src/dbus_wrappers/mod.rs b/src/dbus_wrappers/mod.rs
index 6c9a830e01ec1e3474a139e4cf70db0f3d829634..c0359da04ef23e268ccbac93f6554758685f9c5a 100644
--- a/src/dbus_wrappers/mod.rs
+++ b/src/dbus_wrappers/mod.rs
@@ -1,7 +1,9 @@
 pub mod active_connection;
 pub mod connection;
+pub mod connectivity_state;
 pub mod device;
 pub mod device_state;
 pub mod manager;
 pub mod manager_settings;
-pub mod signal;
\ No newline at end of file
+pub mod signal;
+pub mod state;
\ No newline at end of file
diff --git a/src/dbus_wrappers/state.rs b/src/dbus_wrappers/state.rs
new file mode 100644
index 0000000000000000000000000000000000000000..81852d8ee2d0e9ac2b5e64fac8f18684e7327cc2
--- /dev/null
+++ b/src/dbus_wrappers/state.rs
@@ -0,0 +1,16 @@
+use num_derive::FromPrimitive;
+use serde_derive::{Deserialize, Serialize};
+
+// NMState
+#[derive(FromPrimitive, PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Debug)]
+#[repr(u32)]
+pub enum State {
+    Unknown = 0,
+    Asleep = 10,
+    Disconnected = 20,
+    Disconnecting = 30,
+    Connecting = 40,
+    ConnectedLocal = 50,
+    ConnectedSite = 60,
+    ConnectedGlobal = 70,
+}
\ No newline at end of file
diff --git a/src/event.rs b/src/event.rs
index 5f3c68c7739b0649269109f8b43e00d6ad77a1bd..7101565279ec44bacc710f9397ab56d5d897dc04 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -1,4 +1,4 @@
-use std::sync::Arc;
+use std::{collections::HashSet, sync::Arc};
 
 use anyhow::Result;
 use dbus::nonblock::SyncConnection;
@@ -8,15 +8,31 @@ use tokio::{
     task::JoinHandle,
 };
 
-use crate::{config::Config, identifier::DeviceIdentifier};
+use crate::{config::Config, dbus_wrappers::{connectivity_state::ConnectivityState, state::State}, identifier::DeviceIdentifier};
 
 #[derive(Debug)]
 pub enum Event {
-    DeviceAdded { device_path: dbus::Path<'static> },
-    DeviceRemoved { device_path: dbus::Path<'static> },
-    DeviceActivated { device_path: dbus::Path<'static> },
-    DeviceDeactivating { device_path: dbus::Path<'static> },
-    DeviceDisconnected { device_path: dbus::Path<'static> },
+    ConnectivityStateChanged {
+        connectivity_state: ConnectivityState,
+    },
+    DeviceAdded {
+        device_path: dbus::Path<'static>,
+    },
+    DeviceRemoved {
+        device_path: dbus::Path<'static>,
+    },
+    DeviceActivated {
+        device_path: dbus::Path<'static>,
+    },
+    DeviceDeactivating {
+        device_path: dbus::Path<'static>,
+    },
+    DeviceDisconnected {
+        device_path: dbus::Path<'static>,
+    },
+    StateChanged {
+        state: State,
+    },
 }
 
 pub async fn handle_events(
@@ -45,7 +61,7 @@ pub async fn handle_events(
                             log::warn!("Got an empty event");
                         }
                     }
-                    
+
                 },
                 _ = stop_signal_rx.recv() => {
                     log::info!("Stoping event handler task");
@@ -64,6 +80,9 @@ pub async fn handle_events(
 #[derive(Serialize, Deserialize, Clone, Debug)]
 #[serde(tag = "type")]
 pub enum Trigger {
+    ConnectivityStateChanged {
+        states: HashSet<ConnectivityState>,
+    },
     DeviceAdded {
         device_identifier: Option<DeviceIdentifier>,
     },
@@ -79,11 +98,18 @@ pub enum Trigger {
     DeviceDisconnected {
         device_identifier: Option<DeviceIdentifier>,
     },
+    StateChanged {
+        states: HashSet<State>,
+    },
 }
 
 impl Trigger {
     pub async fn matches_event(&self, conn: &Arc<SyncConnection>, event: &Event) -> Result<bool> {
         match (event, self) {
+            (
+                Event::ConnectivityStateChanged { connectivity_state },
+                Trigger::ConnectivityStateChanged { states },
+            ) => Ok(states.contains(connectivity_state)),
             (Event::DeviceAdded { device_path }, Trigger::DeviceAdded { device_identifier }) => {
                 match device_identifier {
                     Some(device_identified) => {
@@ -138,6 +164,10 @@ impl Trigger {
                 }
                 None => Ok(true),
             },
+            (
+                Event::StateChanged { state },
+                Trigger::StateChanged { states },
+            ) => Ok(states.contains(state)),
             _ => Ok(false),
         }
     }
diff --git a/src/identifier.rs b/src/identifier.rs
index 869d6d0e3809e47cd41b31c22d23680e96b08d39..823429addb10625dedc73e295523ae9b3ef9f669 100644
--- a/src/identifier.rs
+++ b/src/identifier.rs
@@ -33,12 +33,19 @@ impl DeviceIdentifier {
         }
     }
 
-    pub async fn into_device(&self, conn: &Arc<SyncConnection>) -> Result<DeviceWrapper<'static>> {
-        let device_path = self.into_path(conn).await?;
+    pub async fn into_device(&self, conn: &Arc<SyncConnection>) -> Result<Option<DeviceWrapper<'static>>> {
+        match self.into_path(conn).await {
+            Ok(device_path) => {
+                let device = DeviceWrapper::from_path(conn.clone(), device_path).await;
 
-        let device = DeviceWrapper::from_path(conn.clone(), device_path).await;
+                Ok(Some(device))
+            }
+            Err(err) => {
+                log::warn!("Unable to resolve device identifier: {:?} {:?}", self, err);
 
-        Ok(device)
+                Ok(None)
+            },
+        }
     }
 }
 
diff --git a/src/watcher.rs b/src/watcher.rs
index c5f42467754ad85c21bee53aaca5a2efd42f37fe..c05ef28a9e844df731f3b1a93c8948249c85729d 100644
--- a/src/watcher.rs
+++ b/src/watcher.rs
@@ -25,6 +25,7 @@ pub async fn watch(conn: &Arc<SyncConnection>, mut stop_signal_rx: broadcast::Re
 
         let mut device_added_signal = manager.device_added_signal_stream().await?;
         let mut device_removed_signal = manager.device_removed_signal_stream().await?;
+        let mut properties_changed_signal = manager.properties_changed_signal_stream().await?;
 
         log::debug!("Looking for existing devices");
 
@@ -68,6 +69,25 @@ pub async fn watch(conn: &Arc<SyncConnection>, mut stop_signal_rx: broadcast::Re
                         watched_devices.remove(&signal.device_path);
                     }
                 },
+                Some((msg, signal)) = properties_changed_signal.next() => {
+                    log::debug!("Got PropertiesChanged signal for {}: {:?}", signal.interface_name, &msg);
+
+                    if signal.interface_name != "org.freedesktop.NetworkManager" {
+                        break;
+                    }
+
+                    if signal.changed_properties.contains_key("Connectivity") {
+                        event_tx.send(Event::ConnectivityStateChanged {
+                            connectivity_state: manager.get_last_connectivity_state().await?,
+                        }).await?;
+                    }
+
+                    if signal.changed_properties.contains_key("State") {
+                        event_tx.send(Event::StateChanged {
+                            state: manager.get_state().await?,
+                        }).await?;
+                    }
+                }
                 _ = stop_signal_rx.recv() => {
                     log::info!("Stoping NetworkManager watcher task");
 
@@ -80,6 +100,7 @@ pub async fn watch(conn: &Arc<SyncConnection>, mut stop_signal_rx: broadcast::Re
 
         device_added_signal.dispose().await?;
         device_removed_signal.dispose().await?;
+        properties_changed_signal.dispose().await?;
 
         log::debug!("Stopping any remaining child tasks");