diff --git a/Content.Server/Chemistry/Components/ActiveSolutionHeaterComponent.cs b/Content.Server/Chemistry/Components/ActiveSolutionHeaterComponent.cs
new file mode 100644
index 0000000000..b94855ef39
--- /dev/null
+++ b/Content.Server/Chemistry/Components/ActiveSolutionHeaterComponent.cs
@@ -0,0 +1,7 @@
+namespace Content.Server.Chemistry.Components;
+
+[RegisterComponent]
+public sealed class ActiveSolutionHeaterComponent : Component
+{
+
+}
diff --git a/Content.Server/Chemistry/Components/SolutionHeaterComponent.cs b/Content.Server/Chemistry/Components/SolutionHeaterComponent.cs
new file mode 100644
index 0000000000..888f4d2123
--- /dev/null
+++ b/Content.Server/Chemistry/Components/SolutionHeaterComponent.cs
@@ -0,0 +1,19 @@
+namespace Content.Server.Chemistry.Components;
+
+[RegisterComponent]
+public sealed class SolutionHeaterComponent : Component
+{
+ public readonly string BeakerSlotId = "beakerSlot";
+
+ [DataField("heatPerSecond")]
+ public float HeatPerSecond = 120;
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ public float HeatMultiplier = 1;
+
+ [DataField("machinePartHeatPerSecond")]
+ public string MachinePartHeatPerSecond = "Laser";
+
+ [DataField("partRatingHeatMultiplier")]
+ public float PartRatingHeatMultiplier = 1.5f;
+}
diff --git a/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs
new file mode 100644
index 0000000000..47f2d2d981
--- /dev/null
+++ b/Content.Server/Chemistry/EntitySystems/SolutionHeaterSystem.cs
@@ -0,0 +1,65 @@
+using Content.Server.Chemistry.Components;
+using Content.Server.Chemistry.Components.SolutionManager;
+using Content.Server.Construction;
+using Content.Server.Power.Components;
+using Content.Shared.Containers.ItemSlots;
+
+namespace Content.Server.Chemistry.EntitySystems;
+
+public sealed class SolutionHeaterSystem : EntitySystem
+{
+ [Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
+ [Dependency] private readonly SolutionContainerSystem _solution = default!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnPowerChanged);
+ SubscribeLocalEvent(OnRefreshParts);
+ SubscribeLocalEvent(OnUpgradeExamine);
+ }
+
+ private void OnPowerChanged(EntityUid uid, SolutionHeaterComponent component, ref PowerChangedEvent args)
+ {
+ if (args.Powered)
+ {
+ EnsureComp(uid);
+ }
+ else
+ {
+ RemComp(uid);
+ }
+ }
+
+ private void OnRefreshParts(EntityUid uid, SolutionHeaterComponent component, RefreshPartsEvent args)
+ {
+ var heatRating = args.PartRatings[component.MachinePartHeatPerSecond] - 1;
+
+ component.HeatMultiplier = MathF.Pow(component.PartRatingHeatMultiplier, heatRating);
+ }
+
+ private void OnUpgradeExamine(EntityUid uid, SolutionHeaterComponent component, UpgradeExamineEvent args)
+ {
+ args.AddPercentageUpgrade("solution-heater-upgrade-heat", component.HeatMultiplier);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ foreach (var (_, heater) in EntityQuery())
+ {
+ if (_itemSlots.GetItemOrNull(heater.Owner, heater.BeakerSlotId) is not { } item)
+ continue;
+
+ if (!TryComp(item, out var solution))
+ continue;
+
+ var energy = heater.HeatPerSecond * heater.HeatMultiplier * frameTime;
+ foreach (var s in solution.Solutions.Values)
+ {
+ _solution.AddThermalEnergy(solution.Owner, s, energy);
+ }
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/chemistry/components/solution-heater-component.ftl b/Resources/Locale/en-US/chemistry/components/solution-heater-component.ftl
new file mode 100644
index 0000000000..cecf15550c
--- /dev/null
+++ b/Resources/Locale/en-US/chemistry/components/solution-heater-component.ftl
@@ -0,0 +1 @@
+solution-heater-upgrade-heat = Heat strength
diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml
index f62b28da1c..57c8385b1f 100644
--- a/Resources/Prototypes/Catalog/Research/technologies.yml
+++ b/Resources/Prototypes/Catalog/Research/technologies.yml
@@ -103,6 +103,7 @@
- Dropper
- Syringe
- ReagentGrinderMachineCircuitboard
+ - HotplateMachineCircuitboard
- PillCanister
- ChemistryEmptyBottle01
- ChemicalPayload
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index 970ae66ce3..becc60ef10 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -507,6 +507,19 @@
DefaultPrototype: Beaker
ExamineName: Glass Beaker
+- type: entity
+ id: HotplateMachineCircuitboard
+ parent: BaseMachineCircuitboard
+ name: hotplate machine board
+ description: A machine printed circuit board for a hotplate
+ components:
+ - type: MachineBoard
+ prototype: ChemistryHotplate
+ requirements:
+ Laser: 2
+ materialRequirements:
+ Steel: 2
+
- type: entity
id: StasisBedMachineCircuitboard
parent: BaseMachineCircuitboard
diff --git a/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml b/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml
new file mode 100644
index 0000000000..837f8cfaf1
--- /dev/null
+++ b/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml
@@ -0,0 +1,57 @@
+- type: entity
+ id: ChemistryHotplate
+ parent: [ BaseMachinePowered, ConstructibleMachine ]
+ name: hotplate
+ description: "The descendent of the microwaves, our newest invention in beaker heating technology: the hotplate!"
+ components:
+ - type: Transform
+ anchored: true
+ - type: Fixtures
+ fixtures:
+ - shape:
+ !type:PhysShapeAabb
+ bounds: "-0.08,-0.35,0.15,0.25"
+ mask:
+ - TabletopMachineMask
+ layer:
+ - TabletopMachineLayer
+ - type: Sprite
+ netsync: false
+ sprite: Structures/Machines/hotplate.rsi
+ drawdepth: SmallObjects
+ snapCardinals: true
+ layers:
+ - state: icon
+ - state: on
+ map: ["enum.PowerDeviceVisualLayers.Powered"]
+ shader: unshaded
+ - type: ApcPowerReceiver
+ powerLoad: 300
+ - type: ItemSlots
+ slots:
+ beakerSlot:
+ whitelist:
+ components:
+ - FitsInDispenser
+ - type: ItemMapper
+ sprite: Structures/Machines/hotplate.rsi
+ mapLayers:
+ beaker:
+ whitelist:
+ components:
+ - FitsInDispenser
+ - type: SolutionHeater
+ - type: Machine
+ board: HotplateMachineCircuitboard
+ - type: Appearance
+ - type: ContainerContainer
+ containers:
+ beakerSlot: !type:ContainerSlot
+ machine_board: !type:Container
+ machine_parts: !type:Container
+ - type: GenericVisualizer
+ visuals:
+ enum.PowerDeviceVisuals.Powered:
+ enum.PowerDeviceVisualLayers.Powered:
+ True: { visible: true }
+ False: { visible: false }
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 8b06f91dca..1a7d84a844 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -287,6 +287,7 @@
- AutolatheMachineCircuitboard
- ProtolatheMachineCircuitboard
- ReagentGrinderMachineCircuitboard
+ - HotplateMachineCircuitboard
- MicrowaveMachineCircuitboard
- UniformPrinterMachineCircuitboard
- ShuttleConsoleCircuitboard
diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml
index 9d7b811a93..8814b7a76f 100644
--- a/Resources/Prototypes/Recipes/Lathes/electronics.yml
+++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml
@@ -223,6 +223,15 @@
Steel: 100
Glass: 900
+- type: latheRecipe
+ id: HotplateMachineCircuitboard
+ icon: { sprite: Objects/Misc/module.rsi, state: id_mod }
+ result: HotplateMachineCircuitboard
+ completetime: 4
+ materials:
+ Steel: 100
+ Glass: 900
+
- type: latheRecipe
id: AnalysisComputerCircuitboard
icon: { sprite: Objects/Misc/module.rsi, state: cpu_science }
diff --git a/Resources/Textures/Structures/Machines/hotplate.rsi/beaker.png b/Resources/Textures/Structures/Machines/hotplate.rsi/beaker.png
new file mode 100644
index 0000000000..1ca59f7699
Binary files /dev/null and b/Resources/Textures/Structures/Machines/hotplate.rsi/beaker.png differ
diff --git a/Resources/Textures/Structures/Machines/hotplate.rsi/icon.png b/Resources/Textures/Structures/Machines/hotplate.rsi/icon.png
new file mode 100644
index 0000000000..ee6f0599cf
Binary files /dev/null and b/Resources/Textures/Structures/Machines/hotplate.rsi/icon.png differ
diff --git a/Resources/Textures/Structures/Machines/hotplate.rsi/meta.json b/Resources/Textures/Structures/Machines/hotplate.rsi/meta.json
new file mode 100644
index 0000000000..32cd77a8f6
--- /dev/null
+++ b/Resources/Textures/Structures/Machines/hotplate.rsi/meta.json
@@ -0,0 +1 @@
+{"license": "CC0-1.0", "copyright": "Created by EmoGarbage","version": 1, "size": {"x": 32, "y": 32}, "states": [{"name": "icon"}, {"name": "beaker"}, {"name": "on"}]}
diff --git a/Resources/Textures/Structures/Machines/hotplate.rsi/on.png b/Resources/Textures/Structures/Machines/hotplate.rsi/on.png
new file mode 100644
index 0000000000..20582bf810
Binary files /dev/null and b/Resources/Textures/Structures/Machines/hotplate.rsi/on.png differ