Skip to content

Commit

Permalink
feature(flash): Setting a specific brightness
Browse files Browse the repository at this point in the history
  • Loading branch information
oxodao committed Dec 20, 2024
1 parent d2898eb commit e480e5b
Show file tree
Hide file tree
Showing 20 changed files with 209 additions and 54 deletions.
3 changes: 3 additions & 0 deletions admin/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@
"title": "Photobooth",
"amt_manually_taken": "Amount of pictures manually taken",
"amt_unattended": "Amount of pictures unattended",
"flash": "Flash",
"toggle_on": "Turn ON",
"toggle_off": "Turn OFF",
"remote_take_picture": "Remote take picture",
"success_notification": {
"title": "Remote picture",
Expand Down
3 changes: 3 additions & 0 deletions admin/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@
"title": "Photomaton",
"amt_manually_taken": "Photos prises manuellement",
"amt_unattended": "Photos prises automatiquement",
"flash": "Flash",
"toggle_on": "Allumer",
"toggle_off": "Éteindre",
"remote_take_picture": "Prendre une photo",
"success_notification": {
"title": "Prise de photo",
Expand Down
50 changes: 37 additions & 13 deletions admin/src/hooks/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ type AuthProps = {
event: PhEvent | null;
time: DateTime | null;

hardwareFlash: {
powered: boolean;
brightness: number;
};

karaoke: PhKaraoke | null;
karaokeQueue: PhSongSession[];

Expand All @@ -53,6 +58,7 @@ type AuthContextProps = AuthProps & {

setMode: (mode: string) => void;
setEvent: (evt: PhEvent) => void;
setHardwareFlash: (powered: boolean, brightness: number) => void;
setKaraoke: (karaoke: PhKaraoke) => void;
setTimecode: (timecode: number) => void;
setKaraokeQueue: (queue: PhSongSession[]) => void;
Expand All @@ -70,6 +76,11 @@ const defaultProps: AuthProps = {
event: null,
time: null,

hardwareFlash: {
powered: false,
brightness: 100,
},

karaoke: null,
karaokeQueue: [],

Expand All @@ -81,25 +92,32 @@ const defaultProps: AuthProps = {

const AuthContext = createContext<AuthContextProps>({
...defaultProps,
login: async () => {},
loginGuest: async () => {},
setToken: () => {},
login: async () => { },
loginGuest: async () => { },
setToken: () => { },
isLoggedIn: () => false,
logout: () => {},
logout: () => { },

setMode: () => {},
setEvent: () => {},
setKaraoke: () => {},
setTimecode: () => {},
setKaraokeQueue: () => {},
setSyncInProgress: () => {},
setMode: () => { },
setEvent: () => { },
setHardwareFlash: () => { },
setKaraoke: () => { },
setTimecode: () => { },
setKaraokeQueue: () => { },
setSyncInProgress: () => { },

setDisplayName: () => {},
setDisplayName: () => { },
});

export default function AuthProvider({ children }: { children: ReactNode }) {
const [context, setContext] = useState<AuthProps>(defaultProps);
const { topics } = useSettings();
const { topics, hwflash_powered, modules_settings } = useSettings();
const [context, setContext] = useState<AuthProps>({
...defaultProps,
hardwareFlash: {
powered: hwflash_powered,
brightness: modules_settings.photobooth.flash_brightness,
},
});

const login = async (username: string, password: string) => {
const data = await context.api.auth.login(username, password);
Expand Down Expand Up @@ -171,6 +189,11 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
setContext((oldCtx) => ({ ...oldCtx, displayName: displayName }));
};

const setHardwareFlash = (powered: boolean, brightness: number) => setContext((oldCtx) => ({
...oldCtx,
hardwareFlash: { powered, brightness },
}));

useAsyncEffect(async () => {
context.api.setOnExpired(() => setToken());

Expand Down Expand Up @@ -200,6 +223,7 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
isLoggedIn,
logout,
setEvent,
setHardwareFlash,
setMode,
setKaraoke,
setTimecode,
Expand Down
7 changes: 6 additions & 1 deletion admin/src/hooks/mercure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function MercureProvider({
children: ReactNode;
}) {
const [ctx, setCtx] = useState<MercureProps>(defaultProps);
const { setEvent, setMode, isLoggedIn, setSyncInProgress } = useAuth();
const { setEvent, setMode, isLoggedIn, setSyncInProgress, setHardwareFlash } = useAuth();
const [notif, ctxHolder] = notification.useNotification();

const eventSource = useRef<EventSource>();
Expand Down Expand Up @@ -93,6 +93,11 @@ export default function MercureProvider({
setEvent(event);
});

es.addEventListener('/flash', (x) => {
const data = JSON.parse(x.data);
setHardwareFlash(data.powered, data.brightness);
});

es.addEventListener('/mode', (x) => setMode(JSON.parse(x.data).mode));

es.addEventListener('/sync-progress', (x) => setSyncInProgress(JSON.parse(x.data).syncInProgress));
Expand Down
20 changes: 19 additions & 1 deletion admin/src/hooks/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,29 @@ import { ReactNode, createContext, useContext, useState } from 'react';
import Loader from '../components/loader';
import useAsyncEffect from 'use-async-effect';

const DEFAULT_TOPICS = ['/time', '/mode', '/event', '/snackbar', '/karaoke', '/karaoke_queue', '/sync-progress'];
const DEFAULT_TOPICS = [
'/time',
'/mode',
'/event',
'/snackbar',
'/karaoke',
'/karaoke_queue',
'/sync-progress',
'/flash',
];

/** @TODO: Implement APIs */
type SettingsProps = {
loaded: boolean;
pageName: string;

modules_settings: Record<string, any>;

guests_allowed: boolean;
enabled_modules: string[];

hwflash_powered: boolean,

version: string;
commit: string;
hwid: string | null;
Expand All @@ -29,8 +42,13 @@ const defaultProps: SettingsProps = {
pageName: 'home',
topics: DEFAULT_TOPICS,

modules_settings: {},

guests_allowed: false,
enabled_modules: [],

hwflash_powered: false,

version: 'INDEV',
commit: 'XXXXXX',
hwid: null,
Expand Down
35 changes: 32 additions & 3 deletions admin/src/pages/photobooth.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Button, Flex, Typography, notification } from 'antd';
import { Button, Flex, Slider, Tooltip, Typography, notification } from 'antd';
import { IconSun, IconSunOff } from '@tabler/icons-react';
import { useEffect, useState } from 'react';
import KeyVal from '../components/keyval';
import Title from 'antd/es/typography/Title';
import { useAuth } from '../hooks/auth';
import { useEffect } from 'react';
import { useSettings } from '../hooks/settings';
import { useTranslation } from 'react-i18next';

Expand All @@ -11,10 +12,17 @@ export default function Photobooth() {

const [notif, ctxHolder] = notification.useNotification();
const { setPageName } = useSettings();
const { event, api } = useAuth();
const { event, api, hardwareFlash } = useAuth();

const [hwFlashBrightness, setHwFlashBrightness] = useState<number>(hardwareFlash.brightness);

useEffect(() => setPageName('photobooth'), []);

const flashChange = async (powered: boolean, brightness: number) => {
setHwFlashBrightness(brightness);
await api.photobooth.setFlash(powered, brightness);
};

return (
<Flex vertical gap={2}>
<Typography>
Expand All @@ -26,6 +34,27 @@ export default function Photobooth() {
<>
<KeyVal label={t('amt_manually_taken')}>{event.amtImagesHandtaken}</KeyVal>
<KeyVal label={t('amt_unattended')}>{event.amtImagesUnattended}</KeyVal>

<span className="red">{t('flash')}: </span>
<Flex gap={8} align='center'>
<span>{hwFlashBrightness}%</span>

<Slider
style={{flex: 1}}
min={0}
max={100}
value={hwFlashBrightness}
onChange={x => flashChange(hardwareFlash.powered, x)}
/>

<Tooltip title={t(hardwareFlash.powered ? 'toggle_off' : 'toggle_on')}>
<Button
icon={hardwareFlash.powered ? <IconSunOff /> : <IconSun />}
onClick={() => flashChange(!hardwareFlash.powered, hwFlashBrightness)}
/>
</Tooltip>
</Flex>

<Flex style={{ marginTop: '2em' }} vertical>
<Button
onClick={async () => {
Expand Down
1 change: 1 addition & 0 deletions ansible/inventory.yaml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ all:
partyhall_admin_password: 'admin_password'
partyhall_admin_fullname: 'Administrator'

partyhall_photobooth_flash_brightness: 100 # Hardware flash brightness, in percentage
partyhall_photobooth_webcam_width: 1280
partyhall_photobooth_webcam_height: 720

Expand Down
1 change: 1 addition & 0 deletions ansible/templates/partyhall.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ hardware_handler:
settings:
photobooth:
countdown: 3 # Amount of seconds to countdown before taking a picture
flash_brightness: {{ partyhall_photobooth_flash_brightness }} # Hardware flash brightness, in percentage
resolution: # The resolution of your webcam
width: {{ partyhall_photobooth_webcam_width }}
height: {{ partyhall_photobooth_webcam_height }}
Expand Down
5 changes: 3 additions & 2 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ type HardwareHandler struct {

type ModulesSettings struct {
Photobooth struct {
Countdown int `yaml:"countdown" json:"countdown"`
Resolution struct {
Countdown int `yaml:"countdown" json:"countdown"`
FlashBrightness int `yaml:"flash_brightness" json:"flash_brightness"`
Resolution struct {
Width int `yaml:"width" json:"width"`
Height int `yaml:"height" json:"height"`
} `yaml:"resolution" json:"resolution"`
Expand Down
14 changes: 7 additions & 7 deletions backend/hwhandler/hwhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -164,15 +165,14 @@ func (d *Device) OnFlash(c mqtt.Client, m mqtt.Message) {
data := strings.ToLower(string(m.Payload()))
fmt.Println("[MQTT] Flash " + data)

var err error = nil
if data == "on" {
err = d.WriteMessage("FLASH_ON")
} else if data == "off" {
err = d.WriteMessage("FLASH_OFF")
} else {
fmt.Println("\t=> Bad request")
val, err := strconv.Atoi(data)
if err != nil {
fmt.Println("Failed to send flash: bad payload => ", err)

return
}

err = d.WriteMessage(fmt.Sprintf("FLASH %v", val))
if err != nil {
fmt.Println("\t=> Failed to send message to device: " + err.Error())
}
Expand Down
19 changes: 15 additions & 4 deletions backend/hwhandler/hwhandler.ino
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,21 @@ void checkButton(int btn) {
//#endregion

void process_data(const char* data) {
if (strcmp(data, "FLASH_ON") == 0) {
digitalWrite(LEDS_RELAY_PIN, HIGH);
} else if (strcmp(data, "FLASH_OFF") == 0) {
digitalWrite(LEDS_RELAY_PIN, LOW);
char buffer[MAX_INPUT];
strncpy(buffer, data, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';

char* command = strtok(buffer, " ");
char* value_str = strtok(NULL, " ");

if (command && value_str) {
if (strcmp(command, "FLASH") == 0) {
int value = atoi(value_str);

if (value >= 0 && value <= 255) {
analogWrite(LEDS_RELAY_PIN, value);
}
}
}
}

Expand Down
45 changes: 45 additions & 0 deletions backend/mqtt/hw_flash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package mqtt

import (
"fmt"

"github.com/partyhall/partyhall/api_errors"
"github.com/partyhall/partyhall/log"
"github.com/partyhall/partyhall/mercure_client"
"github.com/partyhall/partyhall/state"
"github.com/partyhall/partyhall/utils"
)

func SetFlash(powered bool, brightness int) {
brightness = utils.ClampInt(brightness, 0, 100)
if brightness == 0 {
powered = false
}

state.STATE.ModulesSettings.Photobooth.FlashBrightness = brightness

if !powered {
brightness = 0
}

state.STATE.HardwareFlashPowered = powered

mercure_client.CLIENT.PublishEvent(
"/flash",
map[string]any{
"powered": powered,
"brightness": brightness,
},
)

err := EasyMqtt.Send("partyhall/flash", fmt.Sprintf("%v", brightness))
if err != nil {
api_errors.MQTT_PUBLISH_FAILURE.WithExtra(map[string]any{
"err": err,
})

log.Error("[MQTT] Faied to publish partyhall/flash", "err", err)

return
}
}
Loading

0 comments on commit e480e5b

Please sign in to comment.