Skip to content

Instantly share code, notes, and snippets.

@Kielan
Created December 26, 2025 15:51
Show Gist options
  • Select an option

  • Save Kielan/467d820a2a1fce140c4244ccdeee0761 to your computer and use it in GitHub Desktop.

Select an option

Save Kielan/467d820a2a1fce140c4244ccdeee0761 to your computer and use it in GitHub Desktop.

Revisions

  1. Kielan created this gist Dec 26, 2025.
    123 changes: 123 additions & 0 deletions EnergyHarvester.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,123 @@
    use bevy::prelude::*;

    #[derive(Component)]
    struct Environment {
    humidity: f32, // 0.0 - 1.0
    temperature: f32, // °C
    }

    #[derive(Component)]
    struct Harvester {
    efficiency: f32, // 0.0 - 1.0
    max_power_uw: f32, // microwatts
    }

    #[derive(Component)]
    struct Storage {
    energy_uj: f32, // microjoules
    capacity_uj: f32,
    }

    #[derive(Component)]
    struct Load {
    active: bool,
    draw_uw: f32,
    }

    fn harvest_power(env: &Environment, harvester: &Harvester) -> f32 {
    let gradient = env.humidity * (1.0 - env.humidity);
    let noise = rand::random::<f32>() * 0.2 + 0.9;

    harvester.max_power_uw * gradient * harvester.efficiency * noise
    }

    fn environment_system(mut env: Query<&mut Environment>, time: Res<Time>) {
    for mut env in env.iter_mut() {
    env.humidity += (rand::random::<f32>() - 0.5) * 0.001;
    env.humidity = env.humidity.clamp(0.0, 1.0);
    }
    }

    fn harvesting_system(
    time: Res<Time>,
    env: Query<&Environment>,
    mut query: Query<(&Harvester, &mut Storage)>
    ) {
    let env = env.single();
    let dt = time.delta_seconds();

    for (harvester, mut storage) in query.iter_mut() {
    let power_uw = harvest_power(env, harvester);
    let energy_gained = power_uw * dt;

    storage.energy_uj =
    (storage.energy_uj + energy_gained)
    .min(storage.capacity_uj);
    }
    }

    fn load_system(
    time: Res<Time>,
    mut query: Query<(&mut Storage, &mut Load)>
    ) {
    let dt = time.delta_seconds();

    for (mut storage, mut load) in query.iter_mut() {
    if load.active {
    let drain = load.draw_uw * dt;
    storage.energy_uj -= drain;

    if storage.energy_uj <= 0.0 {
    storage.energy_uj = 0.0;
    load.active = false; // brownout
    }
    }
    }
    }

    fn duty_cycle_system(
    mut query: Query<(&Storage, &mut Load)>,
    ) {
    for (storage, mut load) in query.iter_mut() {
    if storage.energy_uj > 50.0 {
    load.active = true;
    } else {
    load.active = false;
    }
    }
    }

    fn main() {
    App::new()
    .add_plugins(DefaultPlugins)
    .add_systems(Update, (
    environment_system,
    harvesting_system,
    load_system,
    duty_cycle_system,
    ))
    .add_systems(Startup, setup)
    .run();
    }

    fn setup(mut commands: Commands) {
    commands.spawn(Environment {
    humidity: 0.6,
    temperature: 22.0,
    });

    commands.spawn((
    Harvester {
    efficiency: 0.15,
    max_power_uw: 5.0,
    },
    Storage {
    energy_uj: 10.0,
    capacity_uj: 200.0,
    },
    Load {
    active: false,
    draw_uw: 20.0,
    },
    ));
    }