diff --git a/src/ui/panes/pid_drawing_tool.rs b/src/ui/panes/pid_drawing_tool.rs
index 95b9b932c42ba5785e1040600f7b28174266a454..3d91ce0deaa0e06a8cc3d22558988dd4071cbc6b 100644
--- a/src/ui/panes/pid_drawing_tool.rs
+++ b/src/ui/panes/pid_drawing_tool.rs
@@ -113,7 +113,7 @@ impl PaneBehavior for PidPane {
                     if let Some(end) = self.find_hovered_element_idx(&pointer_pos) {
                         if response.clicked() {
                             if start != end {
-                                self.connections.push(Connection::new(start, end));
+                                self.connections.push(Connection::new(start, 0, end, 0));
                                 println!("Added connection from {} to {}", start, end);
                             }
                             self.action.take();
@@ -243,8 +243,9 @@ impl PidPane {
             let mut points = Vec::new();
 
             // Append start point
-            let start = &self.elements[connection.start];
-            points.push(start.position.into_pos2(&self.grid));
+            points.push(
+                self.elements[connection.start].get_ancor_point(&self.grid, connection.start_ancor),
+            );
 
             // Append all midpoints
             connection
@@ -254,8 +255,9 @@ impl PidPane {
                 .for_each(|p| points.push(p));
 
             // Append end point
-            let end = &self.elements[connection.end];
-            points.push(end.position.into_pos2(&self.grid));
+            points.push(
+                self.elements[connection.end].get_ancor_point(&self.grid, connection.end_ancor),
+            );
 
             // Draw line segments
             for i in 0..(points.len() - 1) {
@@ -299,7 +301,7 @@ impl PidPane {
     }
 
     fn draw_context_menu(&mut self, pointer_pos: &Pos2, ui: &mut Ui) {
-        ui.set_max_width(100.0); // To make sure we wrap long text
+        ui.set_max_width(120.0); // To make sure we wrap long text
 
         if self.is_hovering_element(&pointer_pos) {
             let hovered_element = self.find_hovered_element_idx(&pointer_pos);
@@ -342,6 +344,18 @@ impl PidPane {
                 self.connections[conn_idx].split(segm_idx, Pos::from_pos2(&self.grid, pointer_pos));
                 ui.close_menu();
             }
+            if ui.button("Change start ancor").clicked() {
+                let conn = &mut self.connections[conn_idx];
+                conn.start_ancor = (conn.start_ancor + 1)
+                    % self.elements[conn.start].symbol.get_ancor_points().len();
+                ui.close_menu();
+            }
+            if ui.button("Change end ancor").clicked() {
+                let conn = &mut self.connections[conn_idx];
+                conn.end_ancor =
+                    (conn.end_ancor + 1) % self.elements[conn.end].symbol.get_ancor_points().len();
+                ui.close_menu();
+            }
         } else {
             ui.menu_button("Symbols", |ui| {
                 for symbol in Symbol::iter() {
diff --git a/src/ui/panes/pid_drawing_tool/connections.rs b/src/ui/panes/pid_drawing_tool/connections.rs
index e1c9a3b9f3fa1e72c3e74e5003f9de828b794113..43a79ad18ef733c2370b1f9360da57619c9b4ebb 100644
--- a/src/ui/panes/pid_drawing_tool/connections.rs
+++ b/src/ui/panes/pid_drawing_tool/connections.rs
@@ -7,19 +7,23 @@ use super::{grid::LINE_DISTANCE_THRESHOLD, pos::Pos, PidPane};
 pub struct Connection {
     /// Index of the start element
     pub start: usize,
+    pub start_ancor: usize,
 
     /// Index of the end element
     pub end: usize,
+    pub end_ancor: usize,
 
     /// Coordinates of middle points
     pub middle_points: Vec<Pos>,
 }
 
 impl Connection {
-    pub fn new(start: usize, end: usize) -> Self {
+    pub fn new(start: usize, start_ancor: usize, end: usize, end_ancor: usize) -> Self {
         Self {
             start,
+            start_ancor,
             end,
+            end_ancor,
             middle_points: Vec::new(),
         }
     }
@@ -29,8 +33,7 @@ impl Connection {
         let mut points = Vec::new();
 
         // Append start point
-        let start = &pid.elements[self.start];
-        points.push(start.position.into_pos2(&pid.grid));
+        points.push(pid.elements[self.start].get_ancor_point(&pid.grid, self.start_ancor));
 
         // Append all midpoints
         self.middle_points
@@ -39,8 +42,7 @@ impl Connection {
             .for_each(|p| points.push(p));
 
         // Append end point
-        let end = &pid.elements[self.end];
-        points.push(end.position.into_pos2(&pid.grid));
+        points.push(pid.elements[self.end].get_ancor_point(&pid.grid, self.end_ancor));
 
         // Check each segment
         for i in 0..(points.len() - 1) {
diff --git a/src/ui/panes/pid_drawing_tool/elements.rs b/src/ui/panes/pid_drawing_tool/elements.rs
index 97f11363b7d26d088d442b05c5d663a71f433f7b..9b7fdbc805df04c339bffc446fcdaa2691477603 100644
--- a/src/ui/panes/pid_drawing_tool/elements.rs
+++ b/src/ui/panes/pid_drawing_tool/elements.rs
@@ -1,6 +1,6 @@
 use super::symbols::Symbol;
 use super::{grid::GridInfo, pos::Pos};
-use egui::Pos2;
+use egui::{Pos2, Vec2};
 use serde::{Deserialize, Serialize};
 
 #[derive(Clone, Serialize, Deserialize, PartialEq)]
@@ -34,4 +34,11 @@ impl Element {
 
         (start.x <= pos.x && pos.x < end.x) && (start.y <= pos.y && pos.y < end.y)
     }
+
+    pub fn get_ancor_point(&self, grid: &GridInfo, idx: usize) -> Pos2 {
+        let ancor = self.symbol.get_ancor_points()[idx];
+        let ancor = Vec2::from(ancor) * self.size as f32 * grid.size;
+
+        self.position.into_pos2(grid) + ancor
+    }
 }
diff --git a/src/ui/panes/pid_drawing_tool/symbols.rs b/src/ui/panes/pid_drawing_tool/symbols.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1b7b62849f91845bb4feb3f2e5c2e8f7a4779270
--- /dev/null
+++ b/src/ui/panes/pid_drawing_tool/symbols.rs
@@ -0,0 +1,52 @@
+use egui::{ImageSource, Theme};
+use serde::{Deserialize, Serialize};
+use strum_macros::{Display, EnumIter};
+
+#[derive(Clone, Serialize, Deserialize, PartialEq, EnumIter, Display)]
+pub enum Symbol {
+    ManualValve,
+    CheckValve,
+    // ReliefValve,
+    // ControlValve,
+    // PressureRegulator,
+    // BurstDisk,
+    // QuickConnector,
+    // PressureTransducer,
+    // PressureGauge,
+    // FlexibleConnection,
+    // ThreeWayValve,
+    PressurizedVessel,
+}
+
+impl Symbol {
+    pub fn get_image(&self, theme: Theme) -> ImageSource {
+        match (&self, theme) {
+            (Symbol::ManualValve, Theme::Light) => {
+                egui::include_image!("../../../../icons/ball_valve_light.svg")
+            }
+            (Symbol::ManualValve, Theme::Dark) => {
+                egui::include_image!("../../../../icons/ball_valve_dark.svg")
+            }
+            (Symbol::CheckValve, Theme::Light) => {
+                egui::include_image!("../../../../icons/check_valve_light.svg")
+            }
+            (Symbol::CheckValve, Theme::Dark) => {
+                egui::include_image!("../../../../icons/check_valve_dark.svg")
+            }
+            (Symbol::PressurizedVessel, Theme::Light) => {
+                egui::include_image!("../../../../icons/pressurized_vessel_light.svg")
+            }
+            (Symbol::PressurizedVessel, Theme::Dark) => {
+                egui::include_image!("../../../../icons/pressurized_vessel_dark.svg")
+            }
+        }
+    }
+
+    pub fn get_ancor_points(&self) -> Vec<(f32, f32)> {
+        match self {
+            Symbol::ManualValve => [(-0.5, 0.0), (0.5, 0.0)].into(),
+            Symbol::CheckValve => [(-0.5, 0.0), (0.5, 0.0)].into(),
+            Symbol::PressurizedVessel => [(0.0, -0.5), (0.0, 0.5)].into(),
+        }
+    }
+}
diff --git a/src/ui/panes/pid_drawing_tool/symbols/icons.rs b/src/ui/panes/pid_drawing_tool/symbols/icons.rs
new file mode 100644
index 0000000000000000000000000000000000000000..66192cc3f40199b4f83ecec56c3592415186713c
--- /dev/null
+++ b/src/ui/panes/pid_drawing_tool/symbols/icons.rs
@@ -0,0 +1,234 @@
+mod motor_valve;
+
+use egui::{ImageSource, Theme, Ui};
+use glam::Vec2;
+use motor_valve::MotorValve;
+use serde::{Deserialize, Serialize};
+use strum_macros::{Display, EnumIter};
+
+use crate::ui::utils::glam_to_egui;
+
+use super::SymbolBehavior;
+
+#[derive(Clone, Serialize, Deserialize, PartialEq, EnumIter, Display, Debug, Default)]
+pub enum Icon {
+    #[default]
+    Arrow,
+    BurstDisk,
+    CheckValve,
+    FlexibleConnection,
+    ManualValve,
+    MotorValve(MotorValve),
+    PressureGauge,
+    PressureRegulator,
+    PressureTransducer,
+    QuickConnector,
+    ReliefValve,
+    ThreeWayValve,
+    Vessel,
+}
+
+impl Icon {
+    pub fn get_image(&self, theme: Theme) -> ImageSource {
+        match (&self, theme) {
+            (Icon::Arrow, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/arrow.svg")
+            }
+            (Icon::Arrow, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/arrow.svg")
+            }
+            (Icon::BurstDisk, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/burst_disk.svg")
+            }
+            (Icon::BurstDisk, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/burst_disk.svg")
+            }
+            (Icon::ManualValve, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/manual_valve.svg")
+            }
+            (Icon::ManualValve, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/manual_valve.svg")
+            }
+            (Icon::CheckValve, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/check_valve.svg")
+            }
+            (Icon::CheckValve, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/check_valve.svg")
+            }
+            (Icon::ReliefValve, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/relief_valve.svg")
+            }
+            (Icon::ReliefValve, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/relief_valve.svg")
+            }
+            (Icon::MotorValve(state), Theme::Light) => match state.last_value {
+                None => {
+                    egui::include_image!("../../../../../icons/pid_symbols/light/motor_valve.svg")
+                }
+                Some(true) => {
+                    egui::include_image!(
+                        "../../../../../icons/pid_symbols/light/motor_valve_green.svg"
+                    )
+                }
+                Some(false) => {
+                    egui::include_image!(
+                        "../../../../../icons/pid_symbols/light/motor_valve_red.svg"
+                    )
+                }
+            },
+            (Icon::MotorValve(state), Theme::Dark) => match state.last_value {
+                None => {
+                    egui::include_image!("../../../../../icons/pid_symbols/dark/motor_valve.svg")
+                }
+                Some(true) => {
+                    egui::include_image!(
+                        "../../../../../icons/pid_symbols/dark/motor_valve_green.svg"
+                    )
+                }
+                Some(false) => {
+                    egui::include_image!(
+                        "../../../../../icons/pid_symbols/dark/motor_valve_red.svg"
+                    )
+                }
+            },
+            (Icon::ThreeWayValve, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/three_way_valve.svg")
+            }
+            (Icon::ThreeWayValve, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/three_way_valve.svg")
+            }
+            (Icon::PressureRegulator, Theme::Light) => {
+                egui::include_image!(
+                    "../../../../../icons/pid_symbols/light/pressure_regulator.svg"
+                )
+            }
+            (Icon::PressureRegulator, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/pressure_regulator.svg")
+            }
+            (Icon::QuickConnector, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/quick_connector.svg")
+            }
+            (Icon::QuickConnector, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/quick_connector.svg")
+            }
+            (Icon::PressureTransducer, Theme::Light) => {
+                egui::include_image!(
+                    "../../../../../icons/pid_symbols/light/pressure_transducer.svg"
+                )
+            }
+            (Icon::PressureTransducer, Theme::Dark) => {
+                egui::include_image!(
+                    "../../../../../icons/pid_symbols/dark/pressure_transducer.svg"
+                )
+            }
+            (Icon::PressureGauge, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/pressure_gauge.svg")
+            }
+            (Icon::PressureGauge, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/pressure_gauge.svg")
+            }
+            (Icon::FlexibleConnection, Theme::Light) => {
+                egui::include_image!(
+                    "../../../../../icons/pid_symbols/light/flexible_connection.svg"
+                )
+            }
+            (Icon::FlexibleConnection, Theme::Dark) => {
+                egui::include_image!(
+                    "../../../../../icons/pid_symbols/dark/flexible_connection.svg"
+                )
+            }
+            (Icon::Vessel, Theme::Light) => {
+                egui::include_image!("../../../../../icons/pid_symbols/light/vessel.svg")
+            }
+            (Icon::Vessel, Theme::Dark) => {
+                egui::include_image!("../../../../../icons/pid_symbols/dark/vessel.svg")
+            }
+        }
+    }
+}
+
+impl SymbolBehavior for Icon {
+    fn paint(
+        &mut self,
+        ui: &egui::Ui,
+        theme: egui::Theme,
+        pos: glam::Vec2,
+        size: f32,
+        rotation: f32,
+    ) {
+        let center = glam_to_egui(pos).to_pos2();
+        let image_rect = egui::Rect::from_min_size(center, glam_to_egui(self.size() * size));
+        egui::Image::new(self.get_image(theme))
+            .rotate(rotation, egui::Vec2::splat(0.0))
+            .paint_at(ui, image_rect);
+    }
+
+    fn anchor_points(&self) -> Option<Vec<glam::Vec2>> {
+        Some(
+            match self {
+                Icon::Arrow => vec![(0.0, 2.0), (4.0, 2.0)],
+                Icon::BurstDisk => vec![(0.0, 3.0), (4.0, 3.0)],
+                Icon::CheckValve => vec![(0.0, 2.5), (10.0, 2.5)],
+                Icon::FlexibleConnection => vec![(0.0, 3.0), (10.0, 3.0)],
+                Icon::ManualValve => vec![(0.0, 2.5), (10.0, 2.5)],
+                Icon::MotorValve(_) => vec![(0.0, 5.0), (10.0, 5.0)],
+                Icon::PressureGauge => vec![(3.5, 7.0)],
+                Icon::PressureRegulator => vec![(0.0, 7.0), (10.0, 7.0)],
+                Icon::PressureTransducer => vec![(3.5, 7.0)],
+                Icon::QuickConnector => vec![(0.0, 2.5), (6.0, 2.5)],
+                Icon::ReliefValve => vec![(3.0, 10.0)],
+                Icon::ThreeWayValve => vec![(0.0, 3.0), (10.0, 3.0), (5.0, 8.0)],
+                Icon::Vessel => vec![(0.0, 7.6), (8.2, 7.6), (4.1, 0.0), (4.1, 15.1)],
+            }
+            .iter()
+            .map(|&p| p.into())
+            .collect(),
+        )
+    }
+
+    fn size(&self) -> Vec2 {
+        match self {
+            Icon::Arrow => (4.0, 4.0),
+            Icon::BurstDisk => (4.0, 6.0),
+            Icon::CheckValve => (10.0, 5.0),
+            Icon::FlexibleConnection => (10.0, 6.0),
+            Icon::ManualValve => (10.0, 5.0),
+            Icon::MotorValve(_) => (10.0, 8.0),
+            Icon::PressureGauge => (7.0, 7.0),
+            Icon::PressureRegulator => (10.0, 10.0),
+            Icon::PressureTransducer => (7.0, 7.0),
+            Icon::QuickConnector => (6.0, 5.0),
+            Icon::ReliefValve => (6.0, 10.0),
+            Icon::ThreeWayValve => (10.0, 8.0),
+            Icon::Vessel => (8.2, 15.2),
+        }
+        .into()
+    }
+}
+
+/// Single MavLink value source info
+#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
+#[serde(from = "SerialMavlinkValue")]
+struct MavlinkValue {
+    msg_id: u32,
+    field: String,
+
+    #[serde(skip)]
+    view_id: egui::Id,
+}
+
+#[derive(Deserialize)]
+struct SerialMavlinkValue {
+    msg_id: u32,
+    field: String,
+}
+
+impl From<SerialMavlinkValue> for MavlinkValue {
+    fn from(value: SerialMavlinkValue) -> Self {
+        Self {
+            msg_id: value.msg_id,
+            field: value.field,
+            view_id: egui::Id::new(""),
+        }
+    }
+}
diff --git a/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs b/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs
new file mode 100644
index 0000000000000000000000000000000000000000..af4f38f55f56eef934762ba41ab9218be32d8111
--- /dev/null
+++ b/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs
@@ -0,0 +1,60 @@
+use crate::mavlink::{extract_from_message, MavlinkResult, MessageView, TimedMessage};
+
+use super::MavlinkValue;
+
+use serde::{Deserialize, Serialize};
+use skyward_mavlink::{mavlink::MessageData, orion};
+
+#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
+pub struct MotorValve {
+    source: MavlinkValue,
+
+    /// false = closed, true = open
+    pub last_value: Option<bool>,
+}
+
+impl Default for MotorValve {
+    fn default() -> Self {
+        Self {
+            source: MavlinkValue {
+                msg_id: orion::GSE_TM_DATA::ID,
+                field: "n2o_filling_valve_state".to_string(),
+                view_id: egui::Id::new(""),
+            },
+            last_value: None,
+        }
+    }
+}
+
+impl MessageView for MotorValve {
+    fn widget_id(&self) -> &egui::Id {
+        &self.source.view_id
+    }
+
+    fn id_of_interest(&self) -> u32 {
+        self.source.msg_id
+    }
+
+    fn is_valid(&self) -> bool {
+        self.last_value.is_some()
+    }
+
+    fn populate_view(&mut self, msg_slice: &[TimedMessage]) -> MavlinkResult<()> {
+        self.update_view(msg_slice)
+    }
+
+    fn update_view(&mut self, msg_slice: &[TimedMessage]) -> MavlinkResult<()> {
+        if let Some(msg) = msg_slice.last() {
+            let values: MavlinkResult<Vec<Option<u8>>> =
+                extract_from_message(&msg.message, [&self.source.field]);
+            if let Ok(values) = values {
+                if !values.is_empty() {
+                    if let Some(value) = values[0].map(|v| v != 0) {
+                        self.last_value = Some(value);
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/src/ui/panes/pid_drawing_tool/symbols/labels.rs b/src/ui/panes/pid_drawing_tool/symbols/labels.rs
new file mode 100644
index 0000000000000000000000000000000000000000..03c974fa193317cf2695ea64783c076477a012ee
--- /dev/null
+++ b/src/ui/panes/pid_drawing_tool/symbols/labels.rs
@@ -0,0 +1,71 @@
+use serde::{Deserialize, Serialize};
+
+use crate::ui::utils::glam_to_egui;
+
+use super::SymbolBehavior;
+use egui::{Align2, Color32, FontId, Rounding, Stroke, Theme, Ui};
+use glam::Vec2;
+
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
+pub struct Label {
+    last_value: Option<f32>,
+    format_string: String,
+    #[serde(skip)]
+    show_window: bool,
+}
+
+impl SymbolBehavior for Label {
+    fn paint(&mut self, ui: &Ui, theme: Theme, pos: Vec2, size: f32, _: f32) {
+        let painter = ui.painter();
+        let color = match theme {
+            Theme::Light => Color32::BLACK,
+            Theme::Dark => Color32::WHITE,
+        };
+
+        painter.text(
+            glam_to_egui(pos).to_pos2(),
+            Align2::LEFT_TOP,
+            &self.format_string,
+            FontId::monospace(self.size().y * size),
+            color,
+        );
+        painter.rect(
+            egui::Rect::from_min_size(
+                glam_to_egui(pos).to_pos2(),
+                glam_to_egui(self.size()) * size,
+            ),
+            Rounding::ZERO,
+            Color32::TRANSPARENT,
+            Stroke::new(1.0, color),
+        );
+
+        println!("Drawing label edit window {}", self.show_window);
+        let mut show_window = self.show_window;
+        egui::Window::new("Label")
+            .id(ui.id())
+            .auto_sized()
+            .collapsible(false)
+            .movable(true)
+            .open(&mut show_window)
+            .show(ui.ctx(), |ui| {
+                ui.text_edit_singleline(&mut self.format_string);
+            });
+        self.show_window = show_window;
+    }
+
+    fn anchor_points(&self) -> Option<Vec<Vec2>> {
+        None
+    }
+
+    fn size(&self) -> Vec2 {
+        let font_size = 2.0;
+        Vec2::new(font_size * 0.6 * self.format_string.len() as f32, font_size)
+    }
+
+    fn context_menu(&mut self, ui: &mut Ui) {
+        if ui.button("Edit").clicked() {
+            self.show_window = true;
+            ui.close_menu();
+        }
+    }
+}