Migrate telemetry state to publishing (BC) (#22653)

This commit is contained in:
Michael Geers 2025-08-01 11:56:59 +02:00 • committed by GitHub
parent dc7d1a7469
commit ed0b8d6e17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 33 additions and 38 deletions

View file

@ -87,7 +87,7 @@ export default {
}, },
computed: { computed: {
telemetryEnabled() { telemetryEnabled() {
return settings.telemetry === true; return store.state?.telemetry === true;
}, },
hiddenFeatures() { hiddenFeatures() {
return settings.hiddenFeatures === true; return settings.hiddenFeatures === true;

View file

@ -4,7 +4,7 @@
:title="$t('settings.title')" :title="$t('settings.title')"
data-testid="global-settings-modal" data-testid="global-settings-modal"
> >
<UserInterfaceSettings :sponsor="sponsor" /> <UserInterfaceSettings :sponsor="sponsor" :telemetry="telemetry" />
</GenericModal> </GenericModal>
</template> </template>
@ -19,6 +19,7 @@ export default defineComponent({
components: { GenericModal, UserInterfaceSettings }, components: { GenericModal, UserInterfaceSettings },
props: { props: {
sponsor: { type: Object as PropType<Sponsor>, default: () => ({}) }, sponsor: { type: Object as PropType<Sponsor>, default: () => ({}) },
telemetry: Boolean,
}, },
}); });
</script> </script>

View file

@ -58,7 +58,11 @@
/> />
</FormRow> </FormRow>
<FormRow id="telemetryEnabled" :label="$t('settings.telemetry.label')"> <FormRow id="telemetryEnabled" :label="$t('settings.telemetry.label')">
<TelemetrySettings :sponsorActive="sponsor && !!sponsor.name" class="mt-1 mb-0" /> <TelemetrySettings
:sponsorActive="sponsor && !!sponsor.name"
:telemetry="telemetry"
class="mt-1 mb-0"
/>
</FormRow> </FormRow>
<FormRow id="hiddenFeaturesEnabled" :label="`${$t('settings.hiddenFeatures.label')} 🧪`"> <FormRow id="hiddenFeaturesEnabled" :label="`${$t('settings.hiddenFeatures.label')} 🧪`">
<div class="form-check form-switch my-1"> <div class="form-check form-switch my-1">
@ -116,6 +120,7 @@ export default defineComponent({
components: { TelemetrySettings, FormRow, SelectGroup }, components: { TelemetrySettings, FormRow, SelectGroup },
props: { props: {
sponsor: Object as PropType<Sponsor>, sponsor: Object as PropType<Sponsor>,
telemetry: Boolean,
}, },
data() { data() {
return { return {

View file

@ -190,7 +190,10 @@
</div> </div>
<div v-else class="my-4"> <div v-else class="my-4">
<LiveCommunity /> <LiveCommunity />
<TelemetrySettings :sponsorActive="!!sponsor?.name" /> <TelemetrySettings
:sponsorActive="!!sponsor?.name"
:telemetry="telemetry"
/>
</div> </div>
<Sponsor v-bind="sponsor" /> <Sponsor v-bind="sponsor" />
</div> </div>
@ -226,6 +229,7 @@ export default defineComponent({
co2Configured: Boolean, co2Configured: Boolean,
sponsor: Object as PropType<SponsorType>, sponsor: Object as PropType<SponsorType>,
currency: String as PropType<CURRENCY>, currency: String as PropType<CURRENCY>,
telemetry: Boolean,
}, },
data() { data() {
return { return {

View file

@ -153,6 +153,7 @@ export default defineComponent({
smartFeedInPriorityAvailable: Boolean, smartFeedInPriorityAvailable: Boolean,
fatal: Object, fatal: Object,
forecast: Object as PropType<Forecast>, forecast: Object as PropType<Forecast>,
telemetry: Boolean,
}, },
computed: { computed: {
batteryConfigured() { batteryConfigured() {
@ -216,6 +217,7 @@ export default defineComponent({
co2Configured: this.tariffCo2 !== undefined, co2Configured: this.tariffCo2 !== undefined,
priceConfigured: this.tariffGrid !== undefined, priceConfigured: this.tariffGrid !== undefined,
currency: this.currency, currency: this.currency,
telemetry: this.telemetry,
}, },
}; };
}, },

View file

@ -3,7 +3,7 @@
<div class="form-check form-switch my-3"> <div class="form-check form-switch my-3">
<input <input
id="telemetryEnabled" id="telemetryEnabled"
:checked="enabled" :checked="telemetry"
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
role="switch" role="switch"
@ -34,7 +34,6 @@
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import api from "../api"; import api from "../api";
import { docsPrefix } from "../i18n"; import { docsPrefix } from "../i18n";
import settings from "@/settings.ts";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
function parseMarkdown(markdownText: string) { function parseMarkdown(markdownText: string) {
@ -47,54 +46,29 @@ function parseMarkdown(markdownText: string) {
export default defineComponent({ export default defineComponent({
name: "TelemetrySettings", name: "TelemetrySettings",
props: { sponsorActive: Boolean }, props: { sponsorActive: Boolean, telemetry: Boolean },
data() { data() {
return { return {
error: null as string | null, error: null as string | null,
}; };
}, },
computed: { computed: {
enabled() {
return !!settings.telemetry;
},
docsLink() { docsLink() {
return `${docsPrefix()}/docs/faq#telemetry`; return `${docsPrefix()}/docs/faq#telemetry`;
}, },
}, },
async mounted() {
await this.update();
},
methods: { methods: {
async change(e: Event) { async change(e: Event) {
try { try {
this.error = null; this.error = null;
const response = await api.post( await api.post(`settings/telemetry/${(e.target as HTMLInputElement).checked}`);
`settings/telemetry/${(e.target as HTMLInputElement).checked}`
);
settings.telemetry = response.data.result;
} catch (err) { } catch (err) {
const e = err as AxiosError<{ error: string }>; const e = err as AxiosError<{ error: string }>;
if (e.response) { if (e.response) {
this.error = parseMarkdown("**Error:** " + e.response.data.error); this.error = parseMarkdown("**Error:** " + e.response.data.error);
settings.telemetry = false;
} }
} }
}, },
async update() {
if (settings.telemetry !== null) {
return;
}
try {
const response = await api.get("settings/telemetry", {
validateStatus: () => true,
});
if (response.status === 200) {
settings.telemetry = response.data.result;
}
} catch (err) {
console.error(err);
}
},
}, },
}); });
</script> </script>

View file

@ -58,7 +58,6 @@ function saveArray(key: string) {
} }
export interface Settings { export interface Settings {
telemetry: boolean | null; // status is unknown on start
locale: keyof typeof LOCALES | null; locale: keyof typeof LOCALES | null;
theme: THEME | null; theme: THEME | null;
unit: string; unit: string;
@ -78,7 +77,6 @@ export interface Settings {
} }
const settings: Settings = reactive({ const settings: Settings = reactive({
telemetry: null,
locale: read(SETTINGS_LOCALE), locale: read(SETTINGS_LOCALE),
theme: read(SETTINGS_THEME), theme: read(SETTINGS_THEME),
unit: read(SETTINGS_UNIT), unit: read(SETTINGS_UNIT),

View file

@ -189,7 +189,7 @@ func runRoot(cmd *cobra.Command, args []string) {
// setup telemetry // setup telemetry
if err == nil { if err == nil {
telemetry.Create(conf.Plant) telemetry.Create(conf.Plant, valueChan)
if conf.Telemetry { if conf.Telemetry {
err = telemetry.Enable(true) err = telemetry.Enable(true)
} }

View file

@ -154,7 +154,6 @@ func (s *HTTPd) RegisterSiteHandlers(site site.API, valueChan chan<- util.Param)
"sessions": {"GET", "/sessions", sessionHandler}, "sessions": {"GET", "/sessions", sessionHandler},
"updatesession": {"PUT", "/session/{id:[0-9]+}", updateSessionHandler}, "updatesession": {"PUT", "/session/{id:[0-9]+}", updateSessionHandler},
"deletesession": {"DELETE", "/session/{id:[0-9]+}", deleteSessionHandler}, "deletesession": {"DELETE", "/session/{id:[0-9]+}", deleteSessionHandler},
"telemetry": {"GET", "/settings/telemetry", getHandler(telemetry.Enabled)},
"telemetry2": {"POST", "/settings/telemetry/{value:[01truefalse]+}", boolHandler(telemetry.Enable, telemetry.Enabled)}, "telemetry2": {"POST", "/settings/telemetry/{value:[01truefalse]+}", boolHandler(telemetry.Enable, telemetry.Enabled)},
} }

View file

@ -22,6 +22,7 @@ const (
var ( var (
instanceID string instanceID string
publisher chan<- util.Param
mu sync.Mutex mu sync.Mutex
updated time.Time updated time.Time
@ -33,6 +34,13 @@ func Enabled() bool {
return enabled && sponsor.IsAuthorizedForApi() && instanceID != "" return enabled && sponsor.IsAuthorizedForApi() && instanceID != ""
} }
// publish publishes the current telemetry enabled state
func publish() {
if publisher != nil {
publisher <- util.Param{Key: keys.Telemetry, Val: Enabled()}
}
}
func Enable(enable bool) error { func Enable(enable bool) error {
if enable { if enable {
if !sponsor.IsAuthorized() { if !sponsor.IsAuthorized() {
@ -44,16 +52,20 @@ func Enable(enable bool) error {
} }
settings.SetBool(keys.Telemetry, enable) settings.SetBool(keys.Telemetry, enable)
publish()
return nil return nil
} }
func Create(machineID string) { func Create(machineID string, valueChan chan<- util.Param) {
instanceID = machineID instanceID = machineID
publisher = valueChan
if machineID == "" { if machineID == "" {
instanceID = machine.ProtectedID("evcc-api") instanceID = machine.ProtectedID("evcc-api")
} }
publish()
} }
// UpdateChargeProgress uploads power and energy data every 30 seconds // UpdateChargeProgress uploads power and energy data every 30 seconds