Skip to content

Commit

Permalink
feat: add indoor temperature setting (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
ReidyT authored Dec 4, 2024
1 parent 8ec348c commit 1a9d17d
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 5 deletions.
6 changes: 5 additions & 1 deletion src/config/simulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ export const SIMULATION_CSV_FILE = {
measurementFrequency: TimeUnit.Days,
};

export const SIMULATION_INDOOR_TEMPERATURE_CELCIUS = 22;
export const SIMULATION_INDOOR_TEMPERATURE_CELCIUS = {
DEFAULT: 22,
MIN: 5,
MAX: 35,
};
export const SIMULATION_PRICE_KWH = 0.22;

export const SIMULATION_DEFAULT_WALL_COMPONENT_INSULATION: Pick<
Expand Down
7 changes: 5 additions & 2 deletions src/context/SimulationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type SimulationContextType = {
electricityCost: number;
setPricekWh: (newPrice: number) => void;
indoorTemperature: number;
updateIndoorTemperature: (newTemperature: number) => void;
outdoorTemperature: number;
progression: SimulationProgression;
period: SlidingWindow['period'];
Expand Down Expand Up @@ -77,8 +78,9 @@ export const SimulationProvider = ({
unit: TimeUnit.Hours,
});

// TODO: These parameters will be changed by the user
const indoorTemperature = SIMULATION_INDOOR_TEMPERATURE_CELCIUS;
const [indoorTemperature, setOutdoorTemperature] = useState(
SIMULATION_INDOOR_TEMPERATURE_CELCIUS.DEFAULT,
);

const [pricekWh, setPricekWh] = useState(SIMULATION_PRICE_KWH);

Expand Down Expand Up @@ -140,6 +142,7 @@ export const SimulationProvider = ({
const contextValue = useMemo(
() => ({
indoorTemperature,
updateIndoorTemperature: setOutdoorTemperature,
outdoorTemperature: currentWindow.mean,
period: currentWindow.period,
progression,
Expand Down
6 changes: 6 additions & 0 deletions src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
"ELECTRICITY_CONTROL_PANEL": {
"TITLE": "Electricity Cost",
"ELECTRICITY_COST_LABEL": "Electricity Cost"
},
"TEMPERATURES_CONTROL_PANEL": {
"TITLE": "Temperatures",
"INDOOR_TEMPERATURE_LABEL": "Indoor Temperature",
"OUTDOOR_TEMPERATURE_LABEL": "Outdoor Temperature",
"OUTDOOR_TEMPERATURE_OVERRIDE_LABEL": "Outdoor Temperature"
}
},
"INSULATIONS": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import AccordionSummary from '@mui/material/AccordionSummary';

import { ElectricityCostControl } from './ElectricityCostControl';
import { HouseControl } from './HouseControl';
import { TemperatureControl } from './TemperatureControl';

export const SimulationControlPanel = (): JSX.Element => {
const { t } = useTranslation('SIMULATION_CONTROL_PANEL');
Expand Down Expand Up @@ -38,6 +39,19 @@ export const SimulationControlPanel = (): JSX.Element => {
<ElectricityCostControl />
</AccordionDetails>
</Accordion>

<Accordion defaultExpanded>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel-temperature-content"
id="panel-temperature-header"
>
{t('TEMPERATURES_CONTROL_PANEL.TITLE')}
</AccordionSummary>
<AccordionDetails>
<TemperatureControl />
</AccordionDetails>
</Accordion>
</>
);
};
55 changes: 55 additions & 0 deletions src/modules/scenes/SimulationControlPanel/TemperatureControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useTranslation } from 'react-i18next';

import { Slider, Stack, Typography } from '@mui/material';

import { SIMULATION_INDOOR_TEMPERATURE_CELCIUS } from '@/config/simulation';
import { useSimulation } from '@/context/SimulationContext';

export const TemperatureControl = (): JSX.Element => {
const { t } = useTranslation('SIMULATION_CONTROL_PANEL', {
keyPrefix: 'TEMPERATURES_CONTROL_PANEL',
});

const { indoorTemperature, updateIndoorTemperature } = useSimulation();
const { MIN: minTemperature, MAX: maxTemperature } =
SIMULATION_INDOOR_TEMPERATURE_CELCIUS;

const formatTemperature = (value: number): string => `${value} °C`;

return (
<Stack>
<Typography variant="caption">{t('INDOOR_TEMPERATURE_LABEL')}</Typography>

<Stack direction="row" alignItems="flex-start" spacing={2}>
<Stack flexGrow={1}>
<Slider
value={indoorTemperature}
onChange={(_, value) => {
if (typeof value === 'number') {
updateIndoorTemperature(value);
}
}}
valueLabelDisplay="auto"
min={minTemperature}
max={maxTemperature}
role="slider"
aria-label="indoor-temperature"
data-testid="indoor-temperature-slider"
/>
<Stack justifyContent="space-between" direction="row">
<Typography>{formatTemperature(minTemperature)}</Typography>
<Typography>{formatTemperature(maxTemperature)}</Typography>
</Stack>
</Stack>
{/* padding use to align with the slider */}
<Typography
data-testid="indoor-temperature-label"
variant="caption"
pt={0.5}
>
{formatTemperature(indoorTemperature)}
</Typography>
</Stack>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ export const SimulationInformations = (): JSX.Element => {
<Stack direction="row" alignItems="center" spacing={1}>
<ThermometerSun />
<Typography>{tInformations('CURRENT_PERIOD.OUTDOOR')}</Typography>
<Typography>{outdoorTemperature} °C</Typography>
<Typography data-testid="simulation-info-outdoor-temperature">
{outdoorTemperature} °C
</Typography>
</Stack>

<Stack direction="row" alignItems="center" spacing={1}>
<Thermometer />
<Typography>{tInformations('CURRENT_PERIOD.INDOOR')}</Typography>
<Typography>{indoorTemperature} °C</Typography>
<Typography data-testid="simulation-info-indoor-temperature">
{indoorTemperature} °C
</Typography>
</Stack>

<Stack direction="row" alignItems="center" spacing={1}>
Expand Down
17 changes: 17 additions & 0 deletions tests/player/HousePage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Locator, Page, expect } from '@playwright/test';

import { changeSlider } from '../utils/SliderComponent';
import { MaterialEditorPage } from './MaterialEditorPage';
import { WindowEditorPage } from './WindowEditorPage';

Expand All @@ -9,11 +10,16 @@ export class HousePage {

readonly electricityCost: Locator;

readonly indoorTemperatureInfo: Locator;

constructor(page: Page) {
this.page = page;
this.electricityCost = this.page.getByRole('spinbutton', {
name: 'Electricity Cost',
});
this.indoorTemperatureInfo = this.page.getByTestId(
'simulation-info-indoor-temperature',
);
}

async goto(): Promise<void> {
Expand Down Expand Up @@ -56,6 +62,17 @@ export class HousePage {
await expect(this.electricityCost).toHaveValue(newElectricityCost);
}

async setIndoorTemperature(percentage: number): Promise<string> {
const slider = this.page.getByTestId('indoor-temperature-slider');
const sliderLabel = this.page.getByTestId('indoor-temperature-label');
const currValue = (await sliderLabel.textContent()) ?? '';

await changeSlider(this.page, slider, percentage);
await expect(sliderLabel).not.toHaveText(currValue);

return (await sliderLabel.textContent()) ?? '';
}

async checkErrorIsVisible(
label: string,
type: 'Required' | 'Min' | 'Max',
Expand Down
13 changes: 13 additions & 0 deletions tests/player/temperatures.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { expect, test } from '@playwright/test';

import { HousePage } from './HousePage';

test('changing indoor temperature should update the informations', async ({
page,
}) => {
const housePage = new HousePage(page);
await housePage.goto();

const newValue = await housePage.setIndoorTemperature(10);
await expect(housePage.indoorTemperatureInfo).toHaveText(newValue);
});
31 changes: 31 additions & 0 deletions tests/utils/SliderComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Locator, Page, expect } from '@playwright/test';

export const changeSlider = async (
page: Page,
slider: Locator,
targetPercentage: number,
): Promise<void> => {
await expect(slider).toBeVisible();

const sliderBoundingBox = await slider.boundingBox();

if (!sliderBoundingBox) {
throw new Error('SliderBoundingBox is null');
}

const startPoint = {
x: sliderBoundingBox.x,
y: sliderBoundingBox.y + sliderBoundingBox.height / 2,
};

// Slide it to some endpoint determined by the target percentage
const endPoint = {
x: sliderBoundingBox.x + (sliderBoundingBox.width * targetPercentage) / 100,
y: startPoint.y,
};

await page.mouse.move(startPoint.x, startPoint.y);
await page.mouse.down();
await page.mouse.move(endPoint.x, endPoint.y);
await page.mouse.up();
};

0 comments on commit 1a9d17d

Please sign in to comment.