realtime update

Eduardo Gomez Romero 1,095 Reputation points
2024-11-03T01:07:14.06+00:00

I have a service, that is uploading to firestore

 async Task LoadOrInitializeTurbineAsync() {
        var turbinesRef = _firestoreDb!.Collection(collectionName);
        var snapshot = await turbinesRef.GetSnapshotAsync();
        if (snapshot.Count == 0) {
            var turbine = new Turbine {
                Id = "EC-G-SB",
                Country = "Ecuador",
                Name = "Estación Ciudadela Simón Bolívar",
                Address = "Av. de las Américas, Guayaquil 090513, Ecuador",
                Latitude = -2.151993,
                Longitude = -79.886109,
                InstalationDateTime = new DateTime(2024, 8, 2, 0, 0, 0, DateTimeKind.Utc),
                StringifyInstalationDate = DateTime.UtcNow.ToString("D"),
                ImagesURL = [],
            };
            turbine.RemovedCo2Kilograms = Math.Round(turbine.EnergyProduced * turbine.Co2EmissionOffset, 5);
            await AddTurbineImages(turbine);
            var turbineDocRef = turbinesRef.Document(turbine.Id);
            await turbineDocRef.SetAsync(turbine);
            // Add to observable collection if necessary
            AddToObservable(turbine);
        }
        else {
            foreach (var document in snapshot.Documents) {
                var turbine = document.ConvertTo<Turbine>();
                turbine.Id = document.Id;
                await AddTurbineImages(turbine);
                AddToObservable(turbine);
            }
        }
    }
    private async Task AddTurbineImages(Turbine turbine) {
        turbine.ImagesURL!.Clear();
        var containerClient = _blobServiceClient.GetBlobContainerClient(turbine.Country!.ToLower());
        await foreach (var item in containerClient.GetBlobsAsync()) {
            var blobClient = containerClient.GetBlobClient(item.Name);
            turbine.ImagesURL!.Add(blobClient.Uri.ToString());
        }
    }
    private void AddToObservable(Turbine turbine) {
        TurbinePins.Add(new TurbinePin { Turbine = turbine });
    }
    public ObservableCollection<TurbinePin> GetTurbinePinsForUI(ICommand pinClickedCommand) {
        foreach (var pin in TurbinePins.OrderBy(t => t.Turbine?.InstalationDateTime)) {
            pin.PinClickedCommand = pinClickedCommand;
        }
        return TurbinePins;
    }
    private void InitializeTimer() {
        _timer = new System.Timers.Timer(1000); // 1000 milliseconds = 1 second
        _timer.Elapsed += async (sender, e) => await UpdateCO2ValueAsync();
        _timer.AutoReset = true;
        _timer.Enabled = true;
    }
    private async Task UpdateCO2ValueAsync() {
        var turbineRef = _firestoreDb!.Collection("turbines").Document("EC-G-SB");
        var snapshot = await turbineRef.GetSnapshotAsync();
        var turbine = snapshot.ConvertTo<Turbine>();
        // Check initial value before update
        var beforeUpdate = turbine.RemovedCo2Kilograms;
        // Increment and round
        turbine.RemovedCo2Kilograms = Math.Round(beforeUpdate + 0.0007, 5);
        turbine.FinalCo2Removed = turbine.RemovedCo2Kilograms;
        // Debug the values
        Debug.WriteLine($"Before Update: {beforeUpdate}, After Update: {turbine.RemovedCo2Kilograms}");
        await turbineRef.SetAsync(turbine, SetOptions.Overwrite);
    }
}


I have my model


        [FirestoreProperty]
        public string? Id { get; set; }

        [FirestoreProperty]
        public string? Country { get; set; }

        [FirestoreProperty]
        public string? Name { get; set; }

        [FirestoreProperty]
        public string? Address { get; set; }

        [FirestoreProperty]
        public double Power { get; set; } = 0.37;

        [FirestoreProperty]
        public double Co2EmissionOffset { get; set; } = 0.45;

        [FirestoreProperty]
        public double CapacityFactor { get; set; } = 0.25;

        [FirestoreProperty]
        public double Latitude { get; set; }

        [FirestoreProperty]
        public double Longitude { get; set; }

        [FirestoreProperty]
        public DateTime InstalationDateTime { get; set; }

        [FirestoreProperty]
        public List<string>? ImagesURL { get; set; }

        [FirestoreProperty]
        public string? StringifyInstalationDate { get; set; }

        public string? Label => Name; // Keeps the display label for the map

        public Location Location => new(Latitude, Longitude);

        [FirestoreProperty]
        public double EnergyPerDay => RoundToDecimals(Power * CapacityFactor * 24);

        [FirestoreProperty]
        public double EnergyPerHour => RoundToDecimals(EnergyPerDay / 24, 4);

        [FirestoreProperty]
        public double EnergyPerSecond => RoundToDecimals(EnergyPerHour / 60, 5);

        [FirestoreProperty]
        public double RemovedCo2PerSecond => RoundToDecimals(EnergyPerSecond * Co2EmissionOffset, 5);

        [FirestoreProperty]
        public double DaysPassedSinceInstallation => (DateTime.Today - InstalationDateTime).Days;

        [FirestoreProperty]
        public double EnergyProduced => RoundToDecimals(EnergyPerDay * DaysPassedSinceInstallation);

        [FirestoreProperty]
        public double RemovedCo2Kilograms { get; set; }

        [ObservableProperty]
        public double finalCo2Removed;

        private static double RoundToDecimals(double value, int decimals = 2) {
            return Math.Round(value, decimals);
        }

So, I bound this to a custom control

namespace METROWIND.Controls;

public partial class TurbineData : ContentView {
    public TurbineData() {
        InitializeComponent();
    }


    public static readonly BindableProperty TurbineNameProperty = BindableProperty.Create(
        nameof(TurbineName), typeof(string), typeof(TurbineData));

    public string TurbineName {
        get => (string)GetValue(TurbineNameProperty);
        set => SetValue(TurbineNameProperty, value);
    }


    public static readonly BindableProperty TurbineAddresProperty = BindableProperty.Create(
        nameof(TurbineAddres), typeof(string), typeof(TurbineData));

    public string TurbineAddres {
        get => (string)GetValue(TurbineAddresProperty);
        set => SetValue(TurbineAddresProperty, value);
    }


    public static readonly BindableProperty TurbineCreationDateProperty = BindableProperty.Create(
        nameof(TurbineCreationDate), typeof(string), typeof(TurbineData));

    public string TurbineCreationDate {
        get => (string)GetValue(TurbineCreationDateProperty);
        set => SetValue(TurbineCreationDateProperty, value);
    }


    public static readonly BindableProperty Co2KgRemovedProperty = BindableProperty.Create(
        nameof(Co2KgRemoved), typeof(string), typeof(TurbineData));

    public string Co2KgRemoved {
        get => (string)GetValue(Co2KgRemovedProperty);
        set => SetValue(Co2KgRemovedProperty, value);
    }


    public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
        nameof(TapCommand), typeof(ICommand), typeof(TurbineData));

    public ICommand TapCommand {
        get => (ICommand)GetValue(TapCommandProperty);
        set => SetValue(TapCommandProperty, value);
    }

    public static readonly BindableProperty TapCommandParameterProperty = BindableProperty.Create(
           nameof(TapCommandParameter), typeof(object), typeof(TurbineData));

    public object TapCommandParameter {
        get => GetValue(TapCommandParameterProperty);
        set => SetValue(TapCommandParameterProperty, value);
    }
}

 <Border Style="{x:StaticResource CommonBorderStyle}">

     <VerticalStackLayout
         BackgroundColor="#4D9B9B"
         BindingContext="{x:Reference TurbineInfo}"
         Spacing="-10">

         <Label
             FontAttributes="Bold"
             Style="{x:StaticResource TurbineDataLabelStyleStyle}"
             Text="{x:Binding TurbineName}" />

         <Label
             Style="{x:StaticResource TurbineDataLabelStyleStyle}"
             Text="{x:Binding TurbineAddres}" />

         <Label
             Style="{x:StaticResource TurbineDataLabelStyleStyle}"
             Text="{x:Binding TurbineCreationDate}" />

         <Label
             Style="{x:StaticResource C02LabelStyle}"
             Text="{x:Binding Co2KgRemoved, StringFormat='{0:F5} kg CO₂'}" />


I use it here

 <DataTemplate x:Key="turbineTemplte" x:DataType="model:TurbinePin">
        <controls:TurbineData
            Grid.ColumnSpan="2"
            TapCommand="{x:Binding OnPinMarkerClickedCommand,
                                   Source={x:RelativeSource AncestorType={x:Type vm:TurbinesCollectionPageViewModel}}}"
            TapCommandParameter="{x:Binding Turbine}"
            TurbineAddres="{x:Binding Turbine.Address}"
            Co2KgRemoved="{x:Binding Turbine.FinalCo2Removed}"
            TurbineCreationDate="{x:Binding Turbine.StringifyInstalationDate}"
            TurbineName="{x:Binding Turbine.Name}" />
        
    </DataTemplate>


I want to show the update on realtime, bit it dosent work

the change in the co2 in the Ui in my collection view that is using tat template

https://reccloud.com/u/kr1pptr

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,713 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Eduardo Gomez Romero 1,095 Reputation points
    2024-11-05T21:07:39.88+00:00

    I fixed this, by making a new method, to update my observable collection.

    I notice that indeed I was updating my value, and I could see that it was getting updated, but since I get my values on a collectionview, I have to update the value inside my observable

    So I have two values

       [FirestoreProperty]
       public double RemovedCo2Kilograms { get; set; }
    
       [ObservableProperty]
       public double finalCo2Removed;
    
    
    

    one goes to firestone, and the other one goes to my observable

        private async Task UpdateCO2ValueAsync() {
            var turbineRef = _firestoreDb!.Collection(collectionName).Document("EC-G-SB");
            var snapshot = await turbineRef.GetSnapshotAsync();
            var turbine = snapshot.ConvertTo<Turbine>();
    
            // Check initial value before update
            var beforeUpdate = turbine.RemovedCo2Kilograms;
    
            turbine.FinalCo2Removed = beforeUpdate;
    
            // Increment and round
            turbine.RemovedCo2Kilograms = Math.Round(beforeUpdate + 0.0007, 5);
    
            await turbineRef.SetAsync(turbine, SetOptions.Overwrite);
    
            UpdateTurbineInCollection(turbine);
        }
    
        private void UpdateTurbineInCollection(Turbine updatedTurbine) {
    
            var existingTurbinePin = TurbinePins.FirstOrDefault(tp => tp.Turbine!.Id == updatedTurbine.Id);
    
            if (existingTurbinePin != null) {
    
                existingTurbinePin.Turbine!.RemovedCo2Kilograms = updatedTurbine.RemovedCo2Kilograms;
    
                existingTurbinePin.Turbine!.FinalCo2Removed = updatedTurbine.RemovedCo2Kilograms;
            }
        }
    }
    
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.