Skip to content

Commit

Permalink
Ajout logo + animations + historiques
Browse files Browse the repository at this point in the history
fausses données
  • Loading branch information
Potaaaaaaaaaaaato committed Sep 15, 2024
1 parent 32c85c6 commit aa9a11e
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 63 deletions.
Binary file not shown.
21 changes: 21 additions & 0 deletions TTN/Assets.xcassets/logo_iut.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "logo_iut.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 100 additions & 16 deletions TTN/ContentView.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,113 @@
import SwiftUI
import Combine
import Charts
import UserNotifications

struct ContentView: View {
@StateObject private var dataManager = DataManager()
@State private var showHistory = false

var body: some View {
VStack {
Text("Température : \(dataManager.temperature, specifier: "%.2f")°C")
.font(.largeTitle)

Text("Humidité : \(dataManager.humidity, specifier: "%.2f")%")
.font(.title)

List(dataManager.previousData, id: \.temperature) { data in
TabView {
// Page principale avec les valeurs actuelles
VStack(spacing: 20) {

// Logo IUT
Image("logo_iut")
.resizable()
.scaledToFit()
.frame(height: 100)
.padding(.leading, 20) // Garder l'alignement à gauche

// Température avec animation et couleur dynamique
HStack {
Image(systemName: "thermometer.medium")
.font(.system(size: 40))
.foregroundColor(dataManager.temperatureColor)
.scaleEffect(dataManager.temperatureScale)
.animation(.easeInOut(duration: 0.5))
Text("\(dataManager.temperature, specifier: "%.2f")°C")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(dataManager.temperatureColor)
}
.padding(.leading, 20) // Garder l'alignement à gauche

// CO2 avec animation et couleur dynamique
HStack {
Text("Température : \(data.temperature, specifier: "%.2f")°C")
Spacer()
Text("Humidité : \(data.humidity, specifier: "%.2f")%")
Image(systemName: "carbon.dioxide.cloud")
.font(.system(size: 40))
.foregroundColor(dataManager.co2Color)
.scaleEffect(dataManager.co2Scale)
.animation(.easeInOut(duration: 0.5))
Text("\(dataManager.co2, specifier: "%.2f") ppm")
.font(.largeTitle)
.fontWeight(.bold)
.foregroundColor(dataManager.co2Color)
}
.padding(.leading, 20) // Garder l'alignement à gauche

// Graphique des valeurs
Chart(dataManager.previousData) {
LineMark(
x: .value("Temps", $0.time),
y: .value("Température", $0.temperature)
)
.foregroundStyle(.red)

LineMark(
x: .value("Temps", $0.time),
y: .value("CO2", $0.co2)
)
.foregroundStyle(.blue)
}
.frame(height: 200)
.padding(.horizontal, 20) // Espacement horizontal
}
.padding(.top, 10)
.onAppear {
// Activer les notifications locales
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("Notifications autorisées")
} else if let error = error {
print(error.localizedDescription)
}
}

// Rafraîchir toutes les 60 secondes
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
dataManager.fetchData()
}
}
.tabItem {
Image(systemName: "house")
Text("Accueil")
}

// Page Historique
HistoryView(dataManager: dataManager)
.tabItem {
Image(systemName: "clock")
Text("Historique")
}
}
.padding()
.onAppear {
// Rafraîchir toutes les 60 secondes
Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
dataManager.fetchData()
}
}

struct HistoryView: View {
@ObservedObject var dataManager: DataManager

var body: some View {
List(dataManager.previousData, id: \.time) { data in
HStack {
Image(systemName: "thermometer.medium")
Text("Température : \(data.temperature, specifier: "%.2f")°C")

Spacer()

Image(systemName: "carbon.dioxide.cloud")
Text("CO2 : \(data.co2, specifier: "%.2f") ppm")
}
}
}
Expand Down
108 changes: 61 additions & 47 deletions TTN/DataManager.swift
Original file line number Diff line number Diff line change
@@ -1,59 +1,73 @@
import SwiftUI
import Combine

struct DataModel: Identifiable {
var id = UUID() // Ajout de l'identifiant unique
var time: Date
var temperature: Double
var co2: Double
}

class DataManager: ObservableObject {
@Published var temperature: Double = 0.0
@Published var humidity: Double = 0.0
@Published var previousData: [(temperature: Double, humidity: Double)] = []
@Published var co2: Double = 0.0
@Published var previousData: [DataModel] = []

var temperatureColor: Color {
switch temperature {
case ..<15: return .blue
case 15..<25: return .green
case 25..<35: return .orange
default: return .red
}
}

var co2Color: Color {
switch co2 {
case ..<600: return .green
case 600..<1000: return .yellow
default: return .red
}
}

private var cancellable: AnyCancellable?
var temperatureScale: CGFloat {
return temperature > 30 ? 1.2 : 1.0
}

var co2Scale: CGFloat {
return co2 > 1000 ? 1.2 : 1.0
}

func fetchData() {
let urlString = "https://<tenant>.cloud.thethings.network/api/v3/as/applications/<app_id>/devices/<device_id>/packages/storage/uplink_message"
guard let url = URL(string: urlString) else { return }
// Remplacer cette partie par les vraies données de The Things Network
let newTemperature = Double.random(in: 10...40)
let newCO2 = Double.random(in: 300...1200)

// Mise à jour des données actuelles
temperature = newTemperature
co2 = newCO2

var request = URLRequest(url: url)
request.addValue("Bearer <API_KEY>", forHTTPHeaderField: "Authorization")
// Stockage des données précédentes
let newData = DataModel(time: Date(), temperature: newTemperature, co2: newCO2)
previousData.append(newData)

cancellable = URLSession.shared.dataTaskPublisher(for: request)
.tryMap { (data, response) -> Data in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
.decode(type: TTNResponse.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Error fetching data: \(error)")
case .finished:
break
}
}, receiveValue: { [weak self] response in
guard let self = self else { return }

// Stocker les anciennes données
self.previousData.append((temperature: self.temperature, humidity: self.humidity))

// Mettre à jour les nouvelles valeurs
self.temperature = response.uplinkMessage.decodedPayload.temperature
self.humidity = response.uplinkMessage.decodedPayload.humidity
})
// Envoi d'une notification si des valeurs critiques sont dépassées
if newTemperature > 35 {
sendNotification(title: "Température élevée", message: "La température a dépassé 35°C !")
}

if newCO2 > 1000 {
sendNotification(title: "CO2 élevé", message: "Le niveau de CO2 a dépassé 1000 ppm !")
}
}

func sendNotification(title: String, message: String) {
let content = UNMutableNotificationContent()
content.title = title
content.body = message

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
}
}

// Struct pour correspondre à la réponse TTN
struct TTNResponse: Codable {
let uplinkMessage: UplinkMessage
}

struct UplinkMessage: Codable {
let decodedPayload: DecodedPayload
}

struct DecodedPayload: Codable {
let temperature: Double
let humidity: Double
}

0 comments on commit aa9a11e

Please sign in to comment.