Cargando configuración...
;
if (configError) return Datos no disponibles.
;
- const SEVILLA = config?.userConfig.city;
-
- const pollutionData = data.map((measure) => ({
- lat: measure.lat,
- lng: measure.lon,
- level: measure.carbonMonoxide
- }));
-
return (
-
-
-
-
-
+
);
}
-const mapStyles = {
- height: '500px',
- width: '100%',
- borderRadius: '20px'
-};
-
PollutionMap.propTypes = {
groupId: PropTypes.number.isRequired,
deviceId: PropTypes.number.isRequired
diff --git a/frontend/src/components/SummaryCards.jsx b/frontend/src/components/SummaryCards.jsx
index ec30a24..551e176 100644
--- a/frontend/src/components/SummaryCards.jsx
+++ b/frontend/src/components/SummaryCards.jsx
@@ -1,14 +1,10 @@
import PropTypes from 'prop-types';
import CardContainer from './layout/CardContainer';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faCloud, faClock, faTemperature0, faWater } from '@fortawesome/free-solid-svg-icons';
-
import { DataProvider } from '@/context/DataContext';
import { useDataContext } from '@/hooks/useDataContext';
import { useConfig } from '@/hooks/useConfig.js';
-import { DateParser } from '@/util/dateParser';
const SummaryCards = ({ groupId, deviceId }) => {
const { config, configLoading, configError } = useConfig();
@@ -21,7 +17,7 @@ const SummaryCards = ({ groupId, deviceId }) => {
const ENDPOINT = config.appConfig.endpoints.GET_DEVICE_LATEST_VALUES;
const endp = ENDPOINT
.replace(':groupId', groupId)
- .replace(':deviceId', deviceId); // solo si lo necesitas así
+ .replace(':deviceId', deviceId);
const reqConfig = {
baseUrl: `${BASE}${endp}`,
@@ -43,32 +39,29 @@ const SummaryCardsContent = () => {
if (!data) return
Datos no disponibles.
;
const CardsData = [
- { id: 1, title: "Temperatura", content: "N/A", status: "Esperando datos...", titleIcon:
},
- { id: 2, title: "Humedad", content: "N/A", status: "Esperando datos...", titleIcon:
},
- { id: 3, title: "Nivel de CO", content: "N/A", status: "Esperando datos...", titleIcon:
},
- { id: 4, title: "Actualizado a las", content: "N/A", status: "Esperando datos...", titleIcon:
}
+ { id: 1, title: "Temperatura", content: "N/A", status: "Esperando datos...", titleIcon: '🌡 ' },
+ { id: 2, title: "Humedad", content: "N/A", status: "Esperando datos...", titleIcon: '💦 ' },
+ { id: 3, title: "Presión", content: "N/A", status: "Esperando datos...", titleIcon: '⏲ ' },
+ { id: 4, title: "Nivel de CO", content: "N/A", status: "Esperando datos...", titleIcon: '☁ ' }
];
if (data) {
- let coData = data[1];
- let tempData = data[2];
-
- let lastTime = DateParser.timestampToString(coData.timestamp);
- let lastDate = new Date(coData.timestamp);
+ let coData = data[2];
+ let tempData = data[1];
CardsData[0].content = tempData.temperature + "°C";
CardsData[0].status = "Temperatura actual";
CardsData[1].content = tempData.humidity + "%";
CardsData[1].status = "Humedad actual";
- CardsData[2].content = coData.carbonMonoxide + " ppm";
- CardsData[2].status = "Nivel de CO actual";
- CardsData[3].content = lastTime;
- CardsData[3].status = "Día " + lastDate.toLocaleDateString();
+ CardsData[3].content = coData.carbonMonoxide + " ppm";
+ CardsData[3].status = "Nivel de CO actual";
+ CardsData[2].content = tempData.pressure + " hPa";
+ CardsData[2].status = "Presión actual";
}
return (
-
+
);
}
diff --git a/frontend/src/components/layout/Card.jsx b/frontend/src/components/layout/Card.jsx
index 1893a0c..f07296d 100644
--- a/frontend/src/components/layout/Card.jsx
+++ b/frontend/src/components/layout/Card.jsx
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef } from "react";
import "@/css/Card.css";
import { useTheme } from "@/hooks/useTheme";
-const Card = ({ title, status, children, styleMode, className, titleIcon }) => {
+const Card = ({ title, status, children, styleMode, className, titleIcon, style }) => {
const cardRef = useRef(null);
const [shortTitle, setShortTitle] = useState(title);
const { theme } = useTheme();
@@ -30,8 +30,9 @@ const Card = ({ title, status, children, styleMode, className, titleIcon }) => {
ref={cardRef}
className={styleMode === "override" ? `${className}` :
`col-xl-3 col-sm-6 d-flex flex-column align-items-center p-3 card-container ${className}`}
+
>
-
+
{titleIcon}
{shortTitle}
@@ -50,6 +51,7 @@ Card.propTypes = {
styleMode: PropTypes.oneOf(["override", ""]),
className: PropTypes.string,
titleIcon: PropTypes.node,
+ style: PropTypes.object,
};
Card.defaultProps = {
diff --git a/frontend/src/components/layout/CardContainer.jsx b/frontend/src/components/layout/CardContainer.jsx
index 2271a41..1e5253c 100644
--- a/frontend/src/components/layout/CardContainer.jsx
+++ b/frontend/src/components/layout/CardContainer.jsx
@@ -2,20 +2,26 @@ import Card from "./Card.jsx";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
-const CardContainer = ({ links, cards, className }) => {
+const CardContainer = ({ links, cards, className, text }) => {
return (
{cards.map((card, index) => (
links ? (
-
- {card.content}
+
+ {text
+ ? {card.content}
+ : {card.content}
+ }
) : (
-
- {card.content}
-
+
+ {text
+ ? {card.content}
+ : {card.content}
+ }
+
)
))}
@@ -24,6 +30,7 @@ const CardContainer = ({ links, cards, className }) => {
CardContainer.propTypes = {
links: Boolean,
+ text: Boolean,
cards: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
diff --git a/frontend/src/components/layout/ContentWrapper.jsx b/frontend/src/components/layout/ContentWrapper.jsx
new file mode 100644
index 0000000..82d0f6a
--- /dev/null
+++ b/frontend/src/components/layout/ContentWrapper.jsx
@@ -0,0 +1,16 @@
+import PropTypes from 'prop-types';
+
+const ContentWrapper = ({ children, className }) => {
+ return (
+
+ {children}
+
+ );
+}
+
+ContentWrapper.propTypes = {
+ children: PropTypes.node.isRequired,
+ className: PropTypes.string,
+}
+
+export default ContentWrapper;
\ No newline at end of file
diff --git a/frontend/src/components/layout/CustomContainer.jsx b/frontend/src/components/layout/CustomContainer.jsx
new file mode 100644
index 0000000..6d14ffb
--- /dev/null
+++ b/frontend/src/components/layout/CustomContainer.jsx
@@ -0,0 +1,15 @@
+import PropTypes from 'prop-types';
+
+const CustomContainer = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+}
+
+CustomContainer.propTypes = {
+ children: PropTypes.node.isRequired,
+}
+
+export default CustomContainer;
\ No newline at end of file
diff --git a/frontend/src/components/layout/Header.jsx b/frontend/src/components/layout/Header.jsx
index 57ec2a2..51ea32d 100644
--- a/frontend/src/components/layout/Header.jsx
+++ b/frontend/src/components/layout/Header.jsx
@@ -1,20 +1,29 @@
-import PropTypes from 'prop-types';
import '@/css/Header.css';
import { useTheme } from "@/hooks/useTheme";
+import PropTypes from 'prop-types';
+import { Link } from 'react-router-dom';
const Header = ({ subtitle }) => {
const { theme } = useTheme();
return (
-
-
- {subtitle}
+
+
+
+

+
+
+ {subtitle}
+ {/* */}
);
}
Header.propTypes = {
- subtitle: PropTypes.string
-}
+ subtitle: PropTypes.string,
+};
export default Header;
\ No newline at end of file
diff --git a/frontend/src/components/layout/MenuButton.jsx b/frontend/src/components/layout/MenuButton.jsx
deleted file mode 100644
index 28cb0aa..0000000
--- a/frontend/src/components/layout/MenuButton.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import "@/css/MenuButton.css";
-
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faBars } from '@fortawesome/free-solid-svg-icons';
-import PropTypes from "prop-types";
-
-const MenuButton = ({ onClick }) => {
- return (
-
- );
-}
-
-MenuButton.propTypes = {
- onClick: PropTypes.func.isRequired,
-};
-
-export default MenuButton;
\ No newline at end of file
diff --git a/frontend/src/components/layout/SideMenu.jsx b/frontend/src/components/layout/SideMenu.jsx
deleted file mode 100644
index f7e311a..0000000
--- a/frontend/src/components/layout/SideMenu.jsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import "@/css/SideMenu.css";
-import PropTypes from 'prop-types';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faTimes, faHome } from '@fortawesome/free-solid-svg-icons';
-
-import { DataProvider } from '@/context/DataContext';
-import { useDataContext } from "@/hooks/useDataContext";
-
-import { useConfig } from '@/hooks/useConfig.js';
-import { useTheme } from "@/hooks/useTheme";
-
-import { Link } from 'react-router-dom';
-
-import Card from './Card';
-
-const SideMenu = ({ isOpen, onClose }) => {
- const { config, configLoading, configError } = useConfig();
-
- if (configLoading) return Cargando configuración...
;
- if (configError) return Error al cargar configuración: {configError}
;
- if (!config) return Configuración no disponible.
;
-
- const BASE = config.appConfig.endpoints.DATA_URL;
- const ENDPOINT = config.appConfig.endpoints.GET_GROUPS;
-
- const reqConfig = {
- baseUrl: `${BASE}${ENDPOINT}`,
- params: {}
- }
-
- return (
-
-
-
- );
-};
-
-const SideMenuContent = ({ isOpen, onClose }) => {
- const { data, dataLoading, dataError } = useDataContext();
- const { theme } = useTheme();
-
- if (dataLoading) return Cargando datos...
;
- if (dataError) return Error al cargar datos: {dataError}
;
- if (!data) return Datos no disponibles.
;
-
- return (
-
-
-
-
-
- {data.map(group => {
- return (
-
-
- {[]}
-
-
- );
- })}
-
-
- );
-};
-
-SideMenu.propTypes = {
- isOpen: PropTypes.bool.isRequired,
- onClose: PropTypes.func.isRequired
-}
-
-SideMenuContent.propTypes = {
- isOpen: PropTypes.bool.isRequired,
- onClose: PropTypes.func.isRequired
-}
-
-export default SideMenu;
\ No newline at end of file
diff --git a/frontend/src/context/ConfigContext.jsx b/frontend/src/context/ConfigContext.jsx
index 25b59bc..cff1bbc 100644
--- a/frontend/src/context/ConfigContext.jsx
+++ b/frontend/src/context/ConfigContext.jsx
@@ -13,7 +13,7 @@ export const ConfigProvider = ({ children }) => {
try {
const response = import.meta.env.MODE === 'production'
? await fetch("/config/settings.prod.json")
- : await fetch("/config/settings.dev.json");
+ : await fetch("/config/settings.prod.json");
if (!response.ok) throw new Error("Error al cargar settings.*.json");
const json = await response.json();
setConfig(json);
diff --git a/frontend/src/css/HistoryCharts.css b/frontend/src/css/HistoryCharts.css
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/css/Map.css b/frontend/src/css/Map.css
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/css/MenuButton.css b/frontend/src/css/MenuButton.css
deleted file mode 100644
index a2ba7b7..0000000
--- a/frontend/src/css/MenuButton.css
+++ /dev/null
@@ -1,26 +0,0 @@
-.menuBtn {
- position: fixed;
- top: 20px;
- left: 20px;
- z-index: 1000;
- border: none;
- width: 50px;
- height: 50px;
- font-size: 24px; /* Aumenta el tamaño del icono */
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--primary-color);
- background-color: transparent;
- cursor: pointer;
- transition: background-color 0.3s, transform 0.3s;
-}
-
-.menuBtn .fa-bars {
- width: 30px; /* Ajusta el ancho del icono */
- height: 30px; /* Ajusta la altura del icono */
-}
-
-.menuBtn:hover {
- color: var(--secondary-color);
-}
\ No newline at end of file
diff --git a/frontend/src/css/SideMenu.css b/frontend/src/css/SideMenu.css
deleted file mode 100644
index 920435c..0000000
--- a/frontend/src/css/SideMenu.css
+++ /dev/null
@@ -1,90 +0,0 @@
-.side-menu {
- position: fixed;
- top: 0;
- left: -350px;
- width: 350px;
- height: 100%;
- transition: left 0.3s ease;
- padding: 30px;
- box-shadow: 2px 0 5px rgba(0,0,0,0.5);
- z-index: 1000;
-}
-
-.side-menu.light {
- background-color: white;
- color: black;
-}
-
-.side-menu.dark {
- background-color: #333;
- color: white;
-}
-
-.side-menu.open {
- left: 0;
-}
-
-.blur {
- filter: blur(5px);
- transition: filter 0.3s ease;
-}
-
-.side-menu .close-btn {
- position: absolute;
- top: 20px;
- right: 20px;
- background: none;
- border: none;
- font-size: 30px;
- cursor: pointer;
-}
-
-.side-menu .close-btn.light {
- color: black;
-}
-
-.side-menu .close-btn.dark {
- color: white;
-}
-
-.side-menu .close-btn .fa-times {
- width: 30px;
- height: 30px;
-}
-
-.side-menu .close-btn:hover {
- color: var(--primary-color);
-}
-
-.side-menu .home-btn {
- position: absolute;
- top: 20px;
- left: 20px;
- background: none;
- border: none;
- font-size: 30px;
- cursor: pointer;
-}
-
-.side-menu .home-btn .fa-home {
- width: 30px;
- height: 30px;
-}
-
-.side-menu .home-btn.light {
- color: black;
-}
-
-.side-menu .home-btn.dark {
- color: white;
-}
-
-.side-menu .home-btn:hover {
- color: var(--primary-color);
-}
-
-hr.separation {
- margin: 60px 0;
- border: none;
- border-top: 1px solid #ccc;
-}
\ No newline at end of file
diff --git a/frontend/src/css/index.css b/frontend/src/css/index.css
index 772d116..2cd4958 100644
--- a/frontend/src/css/index.css
+++ b/frontend/src/css/index.css
@@ -51,4 +51,3 @@
src: url(https://fonts.gstatic.com/s/poppins/v22/pxiByp8kv8JHgFVrLEj6Z1xlFQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
-
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index 931e19b..ac71e35 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -7,25 +7,6 @@ import App from './App.jsx'
import { ThemeProvider } from './context/ThemeContext.jsx'
import { ConfigProvider } from './context/ConfigContext.jsx'
-/**
- * main.jsx
- *
- * Este archivo es el punto de entrada principal de la aplicación React.
- *
- * Importaciones:
- * - StrictMode: Un componente de React que ayuda a identificar problemas potenciales en la aplicación.
- * - createRoot: Una función de ReactDOM que crea una raíz para renderizar la aplicación.
- * - './css/index.css': Archivo CSS que contiene los estilos globales de la aplicación.
- * - App: El componente principal de la aplicación.
- * - ThemeProvider: Un proveedor de contexto que maneja el tema de la aplicación.
- * - ConfigProvider: Un proveedor de contexto que maneja la configuración de la aplicación.
- *
- * Funcionalidad:
- * - El archivo utiliza `createRoot` para obtener el elemento con el id 'root' del DOM y renderizar la aplicación React dentro de él.
- * - La aplicación se envuelve en `StrictMode` para ayudar a detectar problemas potenciales.
- * - `ThemeProvider` y `ConfigProvider` envuelven el componente `App` para proporcionar los contextos de tema y configuración a toda la aplicación.
- */
-
createRoot(document.getElementById('root')).render(
diff --git a/frontend/src/pages/GroupView.jsx b/frontend/src/pages/GroupView.jsx
index 7defdb5..ee7b6c4 100644
--- a/frontend/src/pages/GroupView.jsx
+++ b/frontend/src/pages/GroupView.jsx
@@ -4,9 +4,36 @@ import LoadingIcon from "@/components/LoadingIcon";
import { useParams } from "react-router-dom";
import { useConfig } from "@/hooks/useConfig";
import { useDataContext } from "@/hooks/useDataContext";
+import { useEffect, useState } from "react";
import { DataProvider } from "@/context/DataContext";
+import { MapContainer, TileLayer, Marker } from 'react-leaflet';
+import L from 'leaflet';
+import 'leaflet/dist/leaflet.css';
+
+// Icono de marcador por defecto (porque Leaflet no lo carga bien en algunos setups)
+const markerIcon = new L.Icon({
+ iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png',
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+});
+
+const MiniMap = ({ lat, lon }) => (
+
+
+
+
+);
+
const GroupView = () => {
const { groupId } = useParams();
const { config, configLoading } = useConfig();
@@ -16,18 +43,48 @@ const GroupView = () => {
const replacedEndpoint = config.appConfig.endpoints.GET_GROUP_DEVICES.replace(':groupId', groupId);
const reqConfig = {
baseUrl: `${config.appConfig.endpoints.DATA_URL}${replacedEndpoint}`,
+ latestValuesUrl: `${config.appConfig.endpoints.LOGIC_URL}${config.appConfig.endpoints.GET_DEVICE_LATEST_VALUES}`,
};
return (
- );
+ );
}
const GroupViewContent = () => {
- const { data, dataLoading, dataError } = useDataContext();
+ const { data, dataLoading, dataError, getData } = useDataContext();
const { groupId } = useParams();
+ const [latestData, setLatestData] = useState({});
+
+ const { config } = useConfig(); // lo pillamos por si acaso
+ const latestValuesUrl = config.appConfig.endpoints.LOGIC_URL + config.appConfig.endpoints.GET_DEVICE_LATEST_VALUES;
+
+ useEffect(() => {
+ if (!data || data.length === 0) return;
+
+ const fetchLatestData = async () => {
+ const results = {};
+
+ await Promise.all(data.map(async device => {
+ const endpoint = latestValuesUrl
+ .replace(':groupId', groupId)
+ .replace(':deviceId', device.deviceId);
+
+ try {
+ const res = await getData(endpoint);
+ results[device.deviceId] = res;
+ } catch (err) {
+ console.error(`Error al obtener latest values de ${device.deviceId}:`, err);
+ }
+ }));
+
+ setLatestData(results);
+ };
+
+ fetchLatestData();
+ }, [data, groupId]);
if (dataLoading) return
;
if (dataError) return Error al cargar datos: {dataError}
;
@@ -35,15 +92,25 @@ const GroupViewContent = () => {
return (
({
- title: device.deviceName,
- status: `ID: ${device.deviceId}`,
- to: `/groups/${groupId}/devices/${device.deviceId}`,
- styleMode: "override",
- className: "col-12 col-md-6 col-lg-4",
- }))}
+ cards={data.map(device => {
+ const latest = latestData[device.deviceId];
+ const gpsSensor = latest?.data[0];
+ const mapPreview = gpsSensor?.lat && gpsSensor?.lon
+ ?
+ : "Sin posición";
+
+ return {
+ title: device.deviceName,
+ status: `ID: ${device.deviceId}`,
+ content: mapPreview,
+ to: `/groups/${groupId}/devices/${device.deviceId}`,
+ styleMode: "override",
+ className: "col-12 col-md-6 col-lg-4"
+ };
+ })}
+
/>
);
-}
+};
export default GroupView;
\ No newline at end of file
diff --git a/frontend/src/pages/Groups.jsx b/frontend/src/pages/Groups.jsx
new file mode 100644
index 0000000..6454032
--- /dev/null
+++ b/frontend/src/pages/Groups.jsx
@@ -0,0 +1,89 @@
+import CardContainer from "@/components/layout/CardContainer";
+import LoadingIcon from "@/components/LoadingIcon";
+
+import { useConfig } from "@/hooks/useConfig";
+import { useDataContext } from "@/hooks/useDataContext";
+
+import { DataProvider } from "@/context/DataContext";
+
+import { useEffect, useState } from "react";
+import PropTypes from "prop-types";
+
+const Groups = () => {
+ const { config, configLoading } = useConfig();
+
+ if (configLoading || !config) return
;
+
+ const replacedEndpoint = config.appConfig.endpoints.GET_GROUPS;
+ const reqConfig = {
+ baseUrl: `${config.appConfig.endpoints.DATA_URL}${replacedEndpoint}`,
+ devicesUrl: `${config.appConfig.endpoints.DATA_URL}${config.appConfig.endpoints.GET_GROUP_DEVICES}`,
+ };
+
+ return (
+
+
+
+ );
+}
+
+const GroupsContent = ({ config }) => {
+ const { data, dataLoading, dataError, getData } = useDataContext();
+ const [devices, setDevices] = useState({});
+
+ useEffect(() => {
+ if (!data || data.length === 0) return;
+
+ const fetchDevices = async () => {
+ const results = {};
+
+ await Promise.all(data.map(async group => {
+ const endpoint = config.devicesUrl
+ .replace(':groupId', group.groupId);
+
+ try {
+ const res = await getData(endpoint);
+ results[group.groupId] = res;
+ } catch (err) {
+ console.error(`Error al obtener dispositivos de ${group.groupId}:`, err);
+ }
+ }));
+
+ setDevices(results);
+ };
+
+ fetchDevices();
+ }, [config.devicesUrl, data, getData]);
+
+ if (dataLoading) return
;
+ if (dataError) return Error al cargar datos: {dataError}
;
+
+ return (
+ {
+ const groupDevices = devices[group.groupId]?.data;
+ const deviceCount = groupDevices?.length;
+
+ return {
+ title: group.groupName,
+ status: `ID: ${group.groupId}`,
+ to: `/groups/${group.groupId}`,
+ styleMode: "override",
+ content: deviceCount != null
+ ? (deviceCount === 1 ? "1 dispositivo" : `${deviceCount} dispositivos`)
+ : "Cargando dispositivos...",
+ className: "col-12 col-md-6 col-lg-4",
+ };
+ })}
+ />
+ );
+}
+GroupsContent.propTypes = {
+ config: PropTypes.shape({
+ devicesUrl: PropTypes.string.isRequired,
+ }).isRequired,
+};
+
+export default Groups;
diff --git a/hardware/src/lib/sensor/BME280.cpp b/hardware/src/lib/sensor/BME280.cpp
index bde5a1c..1561457 100644
--- a/hardware/src/lib/sensor/BME280.cpp
+++ b/hardware/src/lib/sensor/BME280.cpp
@@ -30,5 +30,5 @@ BME280Data_t BME280_Read()
BME280::TempUnit tUnit(BME280::TempUnit_Celsius);
BME280::PresUnit pUnit(BME280::PresUnit_Pa);
bme.read(p, t, h, tUnit, pUnit);
- return {p, t, h};
+ return {p/100, t, h};
}
diff --git a/hardware/src/main.cpp b/hardware/src/main.cpp
index 0726145..f16bcec 100644
--- a/hardware/src/main.cpp
+++ b/hardware/src/main.cpp
@@ -119,7 +119,7 @@ void printAllData()
Serial.println(DEVICE_ID, HEX);
Serial.print("Presión: ");
- Serial.print(bme280Data.pressure / 100);
+ Serial.print(bme280Data.pressure);
Serial.println(" hPa");
Serial.print("Temperatura: ");
Serial.print(bme280Data.temperature);