feat: Refactor automation and site document screens, add device management features, and implement Home Assistant API integration
This commit is contained in:
142
utils/haApi.ts
Normal file
142
utils/haApi.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import { HaArea, HaEntity } from '@/types/types';
|
||||
|
||||
// CONFIGURAZIONE
|
||||
const HA_API_URL = process.env.EXPO_PUBLIC_HA_API_URL;
|
||||
const HA_TOKEN = process.env.EXPO_PUBLIC_HA_TOKEN;
|
||||
|
||||
// Crea un'istanza di axios per Home Assistant
|
||||
const haApi = axios.create({
|
||||
baseURL: HA_API_URL,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${HA_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 5000, // 5 secondi di timeout
|
||||
});
|
||||
|
||||
haApi.interceptors.request.use((config) => {
|
||||
console.log(`[HOME ASSISTANT API REQUEST] ${config.method?.toUpperCase()} ${config.url}`);
|
||||
return config;
|
||||
});
|
||||
|
||||
/*
|
||||
* Connection test
|
||||
*/
|
||||
export const testHaConnection = async (): Promise<{ success: boolean; message: string }> => {
|
||||
// Controlla se le variabili d'ambiente sono caricate
|
||||
if (!HA_API_URL || !HA_TOKEN) {
|
||||
console.error("Variabili d'ambiente per Home Assistant non trovate. Assicurati che EXPO_PUBLIC_HA_API_URL and EXPO_PUBLIC_HA_TOKEN siano definite nel file .env");
|
||||
return { success: false, message: "Configurazione API per Home Assistant mancante." };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await haApi.get('/');
|
||||
// Se la risposta è OK, HA restituisce un JSON con 'message'
|
||||
if (response.status === 200 && response.data.message) {
|
||||
return { success: true, message: response.data.message };
|
||||
}
|
||||
return { success: false, message: "Risposta inattesa dal server Home Assistant." };
|
||||
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
if (axiosError.code === 'ECONNABORTED' || axiosError.message.includes('timeout')) {
|
||||
return { success: false, message: "Timeout: Il server non risponde (IP errato o server offline)." };
|
||||
}
|
||||
|
||||
if (axiosError.response) {
|
||||
// Errori con una risposta dal server (es. 401, 404)
|
||||
if (axiosError.response.status === 401) {
|
||||
return { success: false, message: "Errore 401: Token non autorizzato. Controlla il Long-Lived Token." };
|
||||
}
|
||||
if (axiosError.response.status === 404) {
|
||||
return { success: false, message: "Errore 404: Verifica la configurazione di Home Assistant." };
|
||||
}
|
||||
return { success: false, message: `Errore server: Status ${axiosError.response.status}` };
|
||||
} else if (axiosError.request) {
|
||||
// Errori di rete (la richiesta è partita ma non ha ricevuto risposta)
|
||||
return { success: false, message: `Errore di rete: Impossibile raggiungere ${HA_API_URL}` };
|
||||
} else {
|
||||
// Errore generico
|
||||
return { success: false, message: `Errore sconosciuto: ${axiosError.message}` };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch Home Assistant Areas
|
||||
export const getHaAreas = async (): Promise<HaArea[]> => {
|
||||
try {
|
||||
const response = await haApi.post('/template', {
|
||||
"template": `
|
||||
[
|
||||
{%- for area_id in areas() %}
|
||||
{%- set area_name = area_name(area_id) %}
|
||||
{%- set f_id = floor_id(area_name) %}
|
||||
{%- set f_name = floor_name(f_id) %}
|
||||
{
|
||||
"id": "{{ area_id }}",
|
||||
"name": "{{ area_name }}",
|
||||
"floor_id": {% if f_id != None %}"{{ f_id }}"{% else %}null{% endif %},
|
||||
"floor_name": {% if f_name != None %}"{{ f_name }}"{% else %}null{% endif %},
|
||||
"device_count": {{area_devices(area_id)|count}}
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{%- endfor %}
|
||||
]
|
||||
`
|
||||
});
|
||||
|
||||
const data = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;
|
||||
// console.log("Aree recuperate da Home Assistant:", data);
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error("Errore recupero aree:", error);
|
||||
return []; // Restituisce un array vuoto in caso di errore
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch Home Assistant Entities by Area
|
||||
export const getHaEntitiesByArea = async (areaId: string): Promise<HaEntity[]> => {
|
||||
try {
|
||||
const response = await haApi.post('/template', {
|
||||
"template": `
|
||||
[
|
||||
{%- set area_entities = area_entities('${areaId}') %}
|
||||
{%- for entity_id in area_entities %}
|
||||
{
|
||||
"entity_id": {{ entity_id | tojson }},
|
||||
"name": {{ state_attr(entity_id, 'friendly_name') | tojson }},
|
||||
"state": {{ states(entity_id) | tojson }}
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{%- endfor %}
|
||||
]
|
||||
`
|
||||
});
|
||||
|
||||
const data = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;
|
||||
// console.log(`Entità recuperate per l'area ${areaId}:`, data);
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Errore recupero entità per l'area ${areaId}:`, error);
|
||||
return []; // Restituisce un array vuoto in caso di errore
|
||||
}
|
||||
};
|
||||
|
||||
// Toggle Home Assistant Entity
|
||||
export const toggleHaEntity = async (entityId: string): Promise<boolean> => {
|
||||
try {
|
||||
const domain = entityId.split('.')[0];
|
||||
|
||||
await haApi.post('/services/' + domain + '/toggle', {
|
||||
entity_id: entityId
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Errore toggle ${entityId}:`, error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user