.NET 9 – Swashbuckle vs Scalar

V .NET 9 došlo ke změnám v podpoře pro dokumentaci API. Microsoft odstranil vestavěnou podporu pro Swagger (Swashbuckle) z důvodu nedostatečné údržby tohoto projektu a zaměřil se na integrovanou podporu OpenAPI prostřednictvím balíčku Microsoft.AspNetCore.OpenApi.

Pro interaktivní dokumentaci API nyní existuje alternativa nazvaná Scalar. Jedná se o open-source platformu, která poskytuje moderní a uživatelsky přívětivé rozhraní pro práci s OpenAPI/Swagger dokumenty.

Integrace Scalar do .NET 9 aplikace:

Instalace balíčku: Přidejte balíček Scalar.AspNetCore do svého projektu pomocí následujícího příkazu: add package Scalar.AspNetCore

Nastavení v aplikaci: V souboru Program.cs přidejte potřebné služby a mapování:

using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

app.MapGet("/", () => "Hello world!");

app.Run();


Tímto způsobem bude vaše API dokumentace dostupná na endpointu /scalar/v1

    Přidání Bearer autentizace do Scalar:

    Pokud vaše API využívá Bearer autentizaci, můžete ji integrovat do Scalar pomocí transformátoru:

    Vytvořte třídu transformátoru:

    public sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
    {
        public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
        {
            var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
            if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
            {
                var requirements = new Dictionary<string, OpenApiSecurityScheme>
                {
                    ["Bearer"] = new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.Http,
                        Scheme = "bearer",
                        In = ParameterLocation.Header,
                        BearerFormat = "JWT"
                    }
                };
                document.Components ??= new OpenApiComponents();
                document.Components.SecuritySchemes = requirements;
    
                foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
                {
                    operation.Value.Security.Add(new OpenApiSecurityRequirement
                    {
                        [new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Id = "Bearer",
                                Type = ReferenceType.SecurityScheme
                            }
                        }] = Array.Empty<string>()
                    });
                }
            }
        }
    }

    Registrujte transformátor ve službách:

    builder.Services.AddOpenApi(opt =>
    {
        opt.UseTransformer<BearerSecuritySchemeTransformer>();
    });

      Tímto způsobem zajistíte, že vaše API dokumentace bude správně reflektovat použití Bearer autentizace.

      Více informací o Scalar a jeho integraci do .NET najdete v oficiální dokumentaci: Scalar Guides

      Pyramida řešení problémů: Jak na efektivní a konstruktivní komunikaci

      Řešení konfliktů a problémů je nevyhnutelnou součástí našeho života – ať už v osobním, nebo pracovním prostředí. Často však kvůli emocím, nejasnostem nebo nedostatku struktury narážíme na zbytečné překážky. Jednoduchý, ale velmi účinný nástroj pro řešení takových situací je tzv. pyramida řešení problémů. Tento přístup nás vede k systematickému, konstruktivnímu a respektujícímu způsobu hledání řešení.

      Co je pyramida řešení problémů?

      Pyramida řešení problémů se skládá z pěti klíčových kroků:

      1. Přijetí
      2. Konkretizace
      3. Ověření řešení (budoucího)
      4. Argumentace řešení
      5. Dohoda

      Pojďme si jednotlivé kroky rozepsat a ukázat si, jak je můžeme použít v praxi.

      1. Přijetí: Základ pro konstruktivní diskusi

      První a nejdůležitější krok je přijetí situace nebo problému. To znamená, že uznáme existenci problému a emocí, které mohou být s ním spojené.

      Důležité je vyhýbat se slovu „ale“, které často vyvolává odpor nebo pocit negace. Místo toho používáme „a“, které přidává a rozvíjí diskusi:

      • Špatně: „Rozumím, že tě to trápí, ale nemůžu s tím nic dělat.“
      • Správně: „Rozumím, že tě to trápí, a pojďme najít, co s tím můžeme udělat.“

      Tento krok staví základnu pyramidy a vytváří atmosféru pro vzájemný respekt.

      2. Konkretizace: Hledání jádra pudla

      Jakmile je situace přijatá, je čas dostat se ke kořenů problému. To zahrnuje:

      • Kladení otázek: „Co konkrétně ti vadí?“ „Co je pro tebe největší překážka?“
      • Analyzování situace: „Je tento problém důsledkem jiného problému?“

      Cílem je pochopit, co je opravdu důležité, a vyhnout se řešení povrchních symptomů.

      3. Ověření řešení (budoucího): Plánujme realisticky

      Třetí krok spočívá v hledání a ověření možných řešení. Klíčová otázka zde zní: „Bude to fungovat?“

      Zapojení druhé strany do procesu návrhu řešení zvyšuje jejich ztotožnění s navrženým postupem. Příklady otázek:

      • „Jak by podle tebe mělo vypadat cílové řešení?“
      • „Co by mohlo ohrozit realizaci tohoto návrhu?“

      Tento krok zajišťuje, že navrhované řešení je praktické a proveditelné.

      4. Argumentace řešení: Proč je to dobré

      Jakmile je řešení navržené, je nutné ho podpořit argumenty. Tady můžeme použít:

      • Logické argumenty: „Tento postup je nejrychlejší a nejefektivnější.“
      • Praktické příklady: „V podobné situaci tento postup fungoval velmi dobře.“
      • Empatii: „Rozumím, že to pro tebe může být náročné, ale toto řešení nám všem usnadní práci.“

      Dobře podložená argumentace posiluje důvěru a odhodlání k realizaci řešení.

      5. Dohoda: Společný cíl

      Poslední krok pyramidy je dosažení dohody. Dohoda by měla být:

      • Konkretizovaná: Jasně definujte, kdo co udělá a do kdy.
      • Ověřitelná: „Jak poznáme, že jsme uspěli?“
      • Akceptovaná: Zkontrolujte, že všichni souhlasí a jsou s dohodou spokojeni.

      Shrnutí

      Pyramida řešení problémů nám pomáhá přistupovat k problémům strukturovaně, s respektem a konstruktivním přístupem. Tento model můžeme aplikovat v různých oblastech – od osobních konfliktů po pracovní rozhodování.

      Až příště narazíte na problém, zkuste si vzpomenout na těchto pět kroků. Uvidíte, že cesta k řešení může být mnohem snazší.

      Raspberry Pi čtení dat z teploměru QINGPING Temperature & RH monitor, M version – Xiaomi mi

      Pojďme si ukázat jak číst teplotu a vlhkost z e-link teploměru a vlhkoměru QINGPING Temperature & RH monitor, M version

      Čtení hodnot z Android zařízení

      Do telefonu stáhněte aplikaci Xiaomi Home z Google Play. Na teploměru podržíte zadní tlačítko několik vteřin aby na displeji začala blikat/svítit ikonka bluetooth. Pak v aplikaci dáte vyhledat nové zařízení a objeví se vám dostupné teploměry. Pak postupujete podle instrukcí

      Čtení hodnot z Raspberry Pi

      Aby bylo možné číst teplotu z RaspBerryPi je potřeba v teploměru upravit firmware – tím nebude možné se na teploměr připojit z Android telefonu (viz bod výše)!

      Úpravu firmwate provede podle: https://github.com/pvvx/ATC_MiThermometer

      Úprava firmware probíhá bezdrátově přes bluetooth – není potřeba nic stahovat a speciální znalosti. Stačí notebook s bluetooth. Původní firmware je možné nahrát zpět.

      Aktualizaci provedet vybráním požadovaného teploměru a klikem na tlačítko OTA:

      Na notebooku zapněte Blutooth

      1. Jděte na stránku https://github.com/pvvx/ATC_MiThermometer vyberte teploměr a klikněte na OTA
      2. Několik vteřin podržte zadní tlačítko aby blikala bluetooth ikona
      3. Vstupní pole „BLE device name prefix filter(s):“ můžete nechat prázdné. Tlačítkem „connect“ spustíte prohledávání bluetoth zařízení. Musíte tam najít váš „QINGPING Temp RH M“ se kterým se spárujete. Je potřeba chvilku počkat aby se zobrazil další formulář s tlařítkem „Do Activation“
      4. Tlačítkem „Do Activation“ provedete změnu firmware
      5. Po několika vteřinách skočí do polí „Device known id“, „Mi token“, „Mi bind key“ hodnoty, nahoře na stránce se zobrazí aktuální teplota a vlkost.
      6. vyberete firmwer (tady můžete nahrát i originální) – já vybral CGG1M_V48.bin
      7. Tlačítkem „Start Flashing“ provedete změnu firmware

      Před aktualizací firmware se teploměr jmenoval „Qingping Temp RH M“ a po aktualizaci se jmenoval „CGG_83F48D“

      Připojujeme se z Raspberry Pi

      1. instalce nezbytných nástrojů
      sudo apt-get update
      sudo apt-get install bluez python3-pip
      sudo pip3 install bluepy

      2. zjištění MAC adresy teploměru

      sudo hcitool lescan

      Vypíše se seznam BLE zařízení, mezi nimi hledejte název CGD_XXXXXX.

      3. python script pro čtení teploty

      V tomto scriptu stačí nastavit správnou MAC adresu

      from bluepy.btle import Peripheral
      
      # Nahraď MAC adresu adresou svého teploměru
      MAC_ADDRESS = "83:F4:8D:XX:XX:XX"
      
      def read_temperature(mac):
          try:
              # Připojení k teploměru
              device = Peripheral(mac)
      
              # Čtení dat ze specifického UUID (např. pro teplotu)
              characteristics = device.getCharacteristics(uuid="00002a6e-0000-1000-8000-00805f9b34fb")
              if characteristics:
                  temperature_data = characteristics[0].read()
                  # Konverze získaných dat na teplotu (pokud je třeba)
                  temperature = int.from_bytes(temperature_data, byteorder='little', signed=True) / 100
                  return temperature
      
              device.disconnect()
      
          except Exception as e:
              print(f"Error: {e}")
              return None
      
      temperature = read_temperature(MAC_ADDRESS)
      if temperature is not None:
          print(f"Teplota: {temperature} °C")
      else:
          print("Nelze získat teplotu.")
      

      Script sputíme příkazem:

      ubuntu@ubuntu:~$ python3 temperature.py
      Teplota: 21.65 °C
      

      .NET Dependency Injection (DI)

      Dependency Injection je návrhový vzor, který umožňuje odstranit pevné vazby mezi softwarovými komponentami. Místo přímého vytváření závislých objektů v rámci třídy, DI poskytuje tyto závislosti zvenčí, což vede k větší flexibilitě a oddělení. Ve světě C#, kde aplikace často rostou do velké komplexnosti a musí být snadno testovatelné a rozšiřitelné, je DI klíčovým nástrojem, který vývojářům pomáhá dosáhnout těchto cílů.

      Pojďme si ukázat životní cykly DI služeb – jako jsou Singleton, Scoped a Transient.

      Singleton

      • Životní cyklus: Instance služby Singleton je vytvořena pouze jednou za dobu existence aplikace (nebo hostitele). To znamená, že všechny požadavky a operace používají stejnou instanci služby.
      • Použití: Singleton je vhodný pro služby, které mají globální stav nebo konfiguraci, která se nemění, nebo pro služby, které vyžadují pouze jednu instanci (například logovací služby, přístup k konfiguračním souborům atd.).
      • Rizika: Je třeba být opatrný při používání stavových služeb Singleton ve vícevláknových aplikacích, protože to může vést k problémům s bezpečností vláken.

      Scoped

      • Životní cyklus: Scoped služby jsou vytvořeny jednou pro každý scope, typicky pro každý HTTP požadavek v ASP.NET Core. Každý požadavek má svou vlastní instanci scoped služby.
      • Použití: Scoped služby jsou ideální pro operace, které jsou specifické pro konkrétní požadavek nebo transakci, jako jsou například databázové kontexty v Entity Framework.
      • Rizika: Scoped služby by neměly být sdíleny mezi různými požadavky, protože mohou obsahovat stav specifický pro konkrétní požadavek.

      Transient

      • Životní cyklus: Transient služby jsou vytvářeny pokaždé, když jsou požadovány. To znamená, že každé vložení (injection) nebo každý požadavek na službu vytvoří novou instanci této služby.
      • Použití: Jsou ideální pro lehké, bezstavové služby. Protože jsou transient služby krátkodobé, jsou vhodné pro služby, které neuchovávají informace o stavu nebo zdroje mezi jednotlivými požadavky.
      • Rizika: Vytváření nové instance při každém požadavku může být náročné na zdroje, pokud je služba náročná na vytvoření, nebo pokud je často požadována.

      Shrnutí:

      • Singleton: Jedna instance pro celou aplikaci.
      • Scoped: Jedna instance na scope (typicky na HTTP požadavek).
      • Transient: Nová instance při každém požadavku na službu.

      Při návrhu aplikace je důležité pečlivě zvážit, který životní cyklus je pro každou službu nejvhodnější, aby se dosáhlo správného vyvážení mezi výkonem, bezpečností vláken a správou zdrojů.

      .Net core + NUnit testujeme a mockujeme

      Mockování je důležitým konceptem při psaní jednotkových testů z několika důvodů:

      1. Izolace od závislostí: Mockování umožňuje oddělit testovanou třídu od jejích závislostí. To znamená, že při testování konkrétní třídy nemusíte brát v potaz implementaci jejích závislostí. Místo toho můžete vytvořit mock objekty, které simulují chování těchto závislostí.
      2. Opakovatelnost a konzistence: Při použití skutečných závislostí, jako jsou databáze nebo externí API, mohou testy být nekonzistentní a záviset na stavu těchto závislostí. Použití mocků umožňuje vytvořit konzistentní a opakovatelné testy, které nejsou závislé na externích faktorech.
      3. Rychlost testů: Skutečné závislosti mohou být pomalé nebo nedostupné v určitých situacích, což může zpomalit běh testů. Použití mocků umožňuje rychlejší spouštění testů, protože mocky jsou obvykle rychlejší než skutečné závislosti.
      4. Izolace chyb: Pokud test selže, mocky vám umožňují izolovat problém na konkrétní část kódu, kterou testujete. Bez mocků by selhání mohlo být způsobeno problémem v externí závislosti, což by mohlo být složité odhalit.
      5. Testování hraničních podmínek a chybových stavů: Mocky umožňují snadno simulovat různé situace, včetně chybových stavů, které mohou být obtížné dosáhnout s reálnými závislostmi.
      6. Zvýšení rychlosti vývoje: Testy s mocky umožňují rychlejší iterace při vývoji. Můžete psát testy pro nový kód, i když jeho závislosti nejsou ještě implementovány.
      7. Snížení nákladů na infrastrukturu: Pokud byste všechny testy spouštěli s reálnými závislostmi, mohlo by to vyžadovat drahou infrastrukturu, například databázový server. Mockování umožňuje testování bez skutečné infrastruktury.

      Celkově mockování je důležitou technikou pro vytváření izolovaných a efektivních jednotkových testů, které vám pomáhají zajistit kvalitu kódu a snižovat rizika chyb.

      Instalujeme Moq

      Abychom mohli začít mockovat doinstalujeme Nuget do projektu s testy:

      Install-Package Moq

      Kód pro otestování

      Mějme controller a service, které chceme otestovat. Service se do controlleri injectne přes DI:

      ProductController.cs:

      namespace WebAPiDi.Controllers
      {
          [ApiController]
          [Route("[controller]")]
          public class TestController : ControllerBase
          {
              readonly IProductService _productService;
      
              public TestController(IProductService productService)
              {
                  _productService = productService;
              }
      
              [HttpGet]
              public IActionResult Shop()
              {
                  return Ok(_productService.Shop());
              }
          }
      }

      ProductService.cs:

      namespace WebAPiDi.Services
      {
          public class ProductService : IProductService
          {
              public IEnumerable<ProductDto> Shop()
              {
                  return new List<ProductDto>()
                  {
                      new ProductDto() { Id = 1, Name = "Best product" }
                  };
              }
          }
      }
      

      IProductService.cs:

      namespace WebAPiDi.Services
      {
          public interface IProductService
          {
              IEnumerable<ProductDto> Shop();
          }
      }
      

      productDto.cs:

      namespace WebAPiDi.Dtos
      {
          public class ProductDto
          {
              public int Id { get; set; }
      
              public required string Name { get; set; }
          }
      }
      

      Program.cs (konfigurace sávislostí):

      builder.Services.AddScoped<IProductService, ProductService>();

      Testujeme

      V minulých dílech jsme si ukázali jak zprovoznit NUnit a Moq. Dnes už je jdeme rovnou používat.

      Testujeme service

      Začneme tím jednodušším – otestujme ProducService. Nepotřebujeme nic mockovat, pouze si uděláme instanci ProuctService a zavoláním metody Shop zkontrolujeme že vrátí 1 záznam, ve kterém zkontrolujeme vyplnění propert:

      namespace Test.Services
      {
          [TestFixture]
          public class ProductServiceTests
          {
              [Test]
              public void Shop_ReturnsListOfProducts()
              {
                  // Arrange
                  IProductService productService = new ProductService();
      
                  // Act
                  IEnumerable<ProductDto> products = productService.Shop();
      
                  // Assert
                  Assert.IsNotNull(products);
                  Assert.IsInstanceOf<IEnumerable<ProductDto>>(products);
                  Assert.That(products.Count(), Is.EqualTo(1));
      
                  foreach (var product in products)
                  {
                      Assert.IsNotNull(product.Id);
                      Assert.IsNotNull(product.Name);
                  }
              }
          }
      }

      Při testování controlleru budeme muset použít mockování. Namockujeme se ProductService, čímž vytvoříme izovali od této service a můžeme si nasimulovat nejrůznější chování této service.

      namespace Test.Controllers
      {
          [TestFixture]
          public class TestControllerTests
          {
              [Test]
              public void Shop_ReturnsOkResultWithProducts()
              {
                  // Arrange
                  var productServiceMock = new Mock<IProductService>();
                  productServiceMock.Setup(repo => repo.Shop()).Returns(new List<ProductDto>
                  {
                      new ProductDto() { Id = 68, Name = "Jarda Jagr" },
                      new ProductDto() { Id = 88, Name = "pasta" }
                  });
      
                  var controller = new TestController(productServiceMock.Object);
      
                  // Act
                  var result = controller.Shop() as OkObjectResult;
      
                  // Assert
                  Assert.IsNotNull(result);
                  Assert.That(result.StatusCode, Is.EqualTo(200));
      
                  var products = result.Value as List<ProductDto>;
                  Assert.IsNotNull(products);
                  Assert.That(products.Count, Is.EqualTo(2));
              }
      
              [Test]
              public void Shop_ReturnsEmptyProducts()
              {
                  // Arrange
                  var productServiceMock = new Mock<IProductService>();
                  productServiceMock.Setup(repo => repo.Shop()).Returns(new List<ProductDto>());
      
                  var controller = new TestController(productServiceMock.Object);
      
                  // Act
                  var result = controller.Shop() as OkObjectResult;
      
                  // Assert
                  Assert.IsNotNull(result);
                  Assert.That(result.StatusCode, Is.EqualTo(200));
      
                  var products = result.Value as List<ProductDto>;
                  Assert.IsNotNull(products);
                  Assert.That(products.Count, Is.EqualTo(0));
              }
          }
      }
      

      .Net core + NUnit testujeme statickou třídu

      Testování statických tříd je .Net velice jednoduché. Nemusíte nic mockovat a jednoduše napíšete test. NUnit umožňuje testovat statické třídy stejně jako běžné třídy, ale nemáte k dispozici instanci třídy, takže nemůžete testovat instanční metody ani vlastnosti. Místo toho se zaměříme na testování statických metod a vlastností.

      public static class MathUtility
      {
          public static int Add(int a, int b)
          {
              return a + b;
          }
      
          public static int Subtract(int a, int b)
          {
              return a - b;
          }
      }
      

      Ve Visual Studiu založíme ve stejné solution nový projekt, který bude vycházet ze šablony Nunit Test Project. Do toho projektu založíme nový test:

      namespace Test.Statics
      {
          [TestFixture]
          public class MathUtilityTests
          {
              [Test]
              public void Add_ShouldReturnCorrectSum()
              {
                  int result = MathUtility.Add(3, 5);
                  Assert.AreEqual(8, result);
              }
      
              [Test]
              public void Subtract_ShouldReturnCorrectDifference()
              {
                  int result = MathUtility.Subtract(10, 3);
                  Assert.AreEqual(7, result);
              }
          }
      }
      

      Po spuštění testu (na testovacím projektu klikneme pravým talčítkem a vyberme volbu Run tests) vidíme výsledky testů

      Jak funguje Assert.AreEqual

      Metoda Assert.AreEqual(8, result) v NUnit je způsob, jak otestovat, zda očekávaná hodnota (v tomto případě 8) je rovna aktuální hodnotě (v tomto případě result). Pokud jsou tyto dvě hodnoty shodné, test projde a pokračuje v běhu testů. Pokud jsou hodnoty různé, test selže a testovací běh je přerušen.

      Zde je, jak to funguje:

      • Pokud result (aktuální hodnota) a 8 (očekávaná hodnota) jsou stejné, test projde a není vyvolána výjimka.
      • Pokud result a 8 nejsou stejné, test selže a vyvolá se výjimka AssertionException, která způsobí, že testovací běh se zastaví a označí test jako nevyhovující.

      Tato metoda je používána k porovnání dvou hodnot a určení, zda jsou shodné. Použití této metody v testech je běžným způsobem ověření správného chování kódu. V tomto konkrétním případě se testuje, zda výstup z metody MathUtility.Add(3, 5) je roven 8.

      Poznámka: Můžete také použít jiné metody Assert, jako například Assert.IsTrue, Assert.IsFalse, nebo Assert.IsNull, atd., v závislosti na tom, co chcete otestovat.

      Vylepšení

      Můžete si všimnout, že Visual Studio řádek s ověřením výsledku podtrhne, protože se mu na něm něco nelíbí:

      Assert.AreEqual(8, result);

      U řádku vidíme varování: Consider using the constraint model, Assert.That(actual, Is.EqualTo(expected)), instead of the classic model, Assert.AreEqual(expected, actual).

      Více o problému se dočete zde: https://docs.nunit.org/articles/nunit-analyzers/NUnit2005.html

      Pokud se chcete toto varování opravit, přepište ověření výsledku na:

      Assert.That(result, Is.EqualTo(7));

      Python – monitorujeme aktuální spotřebu přes chytrou zásuvku P110

      Zásuvka Tapo P110 je jedním z produktů od společnosti TP-Link, který umožňuje smart ovládání přes WiFi. Jedna z výhod této zásuvky je, Dnes se podíváme na tuto chytrou zásuvku, kterou budeme na dálku ovládat a měřit spotřebu. Jednou z výhod této zásuvky oproti nižšímu modelu P100 je monitorování spotřeby elektrické energie. To nám umožní sledovat kolik elektřiny jednotlivá zařízení spotřebovávají.

      Dnešní řešení provedeme v programovací m jazyce Python s využitím knihovny PyP100. Nenechte se zmást názvem knihovny PyP100, tato knihovna umí pracovat i se zásvkou P110.

      Neprve zapojte zásuvku do elektřiny, přidejte si ji do vaší domácnosti a zprozněte v aplikaci TAPO.

      Zásuvka komunikuje s okolím přes WiFi, tekže zařízení kterým budete zásvuku ovládat / monitorovat odběr přes zásuvku musí být ve stejné síti. V mém případě se jedná o Raspberry.

      V apliakci je pořeba zjistit IP adresu zásvuky. Provedete to v detailu zásuvky -> Info o zařízení -> IP adresa.

      Instalace Python na Raspberry Pi

      Na Raspberry Pi mám Ubuntu:

      sudo apt update 
      sudo apt upgrade
      sudo apt install python3
      python3 --version

      Programujeme

      Použijeme Python s knihovnu https://pypi.org/project/PyP100/

      sudo pip install PyP100

      V případě chyby:

      error: externally-managed-environment

      × This environment is externally managed
      ╰─> To install Python packages system-wide, try apt install
      python3-xyz, where xyz is the package you are trying to
      install.

      sudo pip install PyP100 --break-system-packages

      Pak už jen napíšeme kód pro ovládání zásvuky. Nezapomeňte, že zásuvku musíte mít přidanou ve va3i aplikaci, protože pro ovládání zásuvky bude potřeba jméno a heslo k vašemu účtu TAPO.

      from PyP100 import PyP110
      
      p110 = PyP100.P110("192.168.X.X", "email@email.cz", "heslo") #IP adresa zasuvky, email, heslo
      
      p110.handshake() #cookies pozadavek
      p110.login()
      
      
      p110.getEnergyUsage() #aktualni spotreba zasuvky
      
      #sprace se stavy zasuvky
      p110.turnOn() #Zapne zasuvku
      p110.turnOff() #Vypne zasuvku
      p110.toggleState() #zmeni stav zasuvky na opacny zapne/vypne
      
      p110.turnOnWithDelay(10) #zapne se zpozdenim 10s
      p110.turnOffWithDelay(10) #vypne se zpozdenim 10s
      
      p110.getDeviceInfo() #informace o zasuvce
      p110.getDeviceName() #jmeno zasuvky

      Ubuntu – jak spustit script po startu systému – služba

      Pro spuštění skriptu po startu systému na Raspberry Pi s operačním systémem Ubuntu, můžete využít službu systému systemd. systemd je systémový a službový správce většiny moderních linuxových distribucí, včetně Ubuntu.

      1. Vytvořte skript, který chcete spustit po startu systému. Scriptu musíte nastavit oprávnění pro spuštění. Například, pokud máte skript ble-advertisements.py, ujistěte se, že má správná oprávnění pro spuštění: chmod +x ble-advertisements.sh.
      2. Vytvořte systemd službu. Vytvořte nový soubor s příponou .service ve složce /etc/systemd/system/. Můžete to provést například pomocí editoru vim:
      sudo vim /etc/systemd/system/ble-advertisements.service

      V tomto souboru jsou informace o službě:

      [Unit]
      Description=BLE advertisements
      
      [Service]
      ExecStart=/home/ubuntu/scripts/ble-advertisements.sh
      WorkingDirectory=/home/ubuntu/scripts
      Restart=always
      User=ubuntu
      
      [Install]
      WantedBy=multi-user.target

      Souboru nastave oprvávnění pro spuštění:

      sudo chmod ugo+x /etc/systemd/system/ble-advertisements.service

      Upravte následující informace podle vašich potřeb:

      • Description – Popis vaší služby.
      • ExecStart – Cesta k vašemu skriptu, který chcete spustit.
      • WorkingDirectory – Volitelně, cesta k pracovní složce, kde se skript spouští.
      • User – Uživatel, pod kterým chcete spustit skript. Zde je uveden uživatel „ubuntu“, ale upravte jej podle vašich potřeb.

      Aktualizujte systemd a povolte vaši službu:

      sudo systemctl daemon-reload
      sudo systemctl enable ble-advertisements.service
      

      Restartujte zařízení. Po restartu se služba automaticky spustí:

      sudo reboot

      Sledování statvu služby

      systemctl status ble-advertisements.service

      journalctl -u ble-advertisements.service

      Změny stavu služby

      systemctl restart ble-advertisements.service
      systemctl stop ble-advertisements.service
      systemctl start ble-advertisements.service

      Entity Framework Core – logování selectů a doby vykonávání

      Časem narazíte na problémy pomalých odezev vašich aplikací. Budete chtít mít představu kdy a jak dlouho co trvalo – kdo neměří ten neřídí. Proto si dnes ukážeme jak logovat vygenerované SQL dotazy včetně jejich časi provedení. Entity Framework defaultně loguje příkazy, které vykonává, ovšem to dost často nestačí. Dnes si ukážeme jak logování rozšířit.

      Zabudovaného logování v EF Core

      Jedná se o základní jedochudou metodu. V Program.cs máte kód který přidává EF do DI:

      //EF
      builder.Services.AddDbContext<HulvatContext>(options =>
      {
          options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection");
      });

      Tento kód stačí rozšířit o požadované logování:

      //EF
      builder.Services.AddDbContext<HulvatContext>(options =>
      {
          options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
          .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()))
          .EnableSensitiveDataLogging();
      });

      Tím získáme SQL dotaz včetně doby vykonávání:

      info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (10ms) [Parameters=[@__email_0='test@test.cz' (Size = 50)], CommandType='Text', CommandTimeout='30']
      SELECT TOP(1) [u].[Id], [u].[DisplayName], [u].[Email], [u].[FisrtName], [u].[LastName] FROM [Users] AS [u]
      WHERE [u].[Email] = @__email_0

      Tímto způsobem budou SQL dotazy logovány do konzole. Můžete změnit cíl logování tím, že nahradíte AddConsole() za jiný logger.

      EnableSensitiveDataLogging

      Při logování SQL dotazů s citlivými daty (sensitive data), můžete použít metodu .EnableSensitiveDataLogging(). Tato metoda zajistí, že citlivá data, jako jsou hesla, nebudou logována.

      .NET core – jak logovat s NLog

      Nes si ukážeme jak zprovoznit logování přes knihovnu NLog. V této knihovně je možné udělat několik targertů a do každého targetu logovat různé informace. Například pouze chyby logovat do speciálního targetu a posílat si je například emailem, …

      Instalace NLog

      Install-Package NLog
      Install-Package NLog.Web.AspNetCore

      Konfigurace NLog

      Vytvoříme soubor konfigurace pro NLog, který určuje, kam a jak mají být logy zpracovány. Vytvořte soubor s názvem „nlog.config“ ve vašem projektu (na úrovni souboru appsettings.json):

      <?xml version="1.0" encoding="utf-8" ?>
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        autoReload="true"
        internalLogLevel="info"
        internalLogFile="c:\\_temp\\internallog.txt">
        <extensions>
          <add assembly="NLog.Web.AspNetCore" />
        </extensions>
        <targets>
          <target name="logfile" xsi:type="File" fileName="c:\\_temp\\log.txt" layout="${longdate} ${level:uppercase=true} ${message}"/>
           <target xsi:type="ColoredConsole" name="logconsole" />
        </targets>
        <rules>
          <logger name="Microsoft.*" maxLevel="Info" final="true" />
          <logger name="*" minlevel="Info" writeTo="logfile" />
          <logger name="*" minlevel="Info" writeTo="logconsole" />
        </rules>
      </nlog>

      Tento konfigurační soubor nastaví logování do souboru „log.txt“ od úrovně „Info“ výše a zahrnuje všechny loggery (názvy hvězdičkou). Můžete dále upravit konfiguraci podle vašich potřeb. Osvědčilo se mi posálání chyb emailem.

      Registrujeme NLog v aplikaci

      Do souboru Program.cs přidáme:

      var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
      
      //Nlog
      builder.Logging.ClearProviders();
      builder.Host.UseNLog();

      Logujeme v aplikaci

      Nyní máme 2 možnosti logování

      Logování přes GetCurrentClassLogger

      Definujeme a rovnou naplníme field logeru:

      private static Logger _logger = LogManager.GetCurrentClassLogger();

      který pak používáme:

      _logger.Trace("Trace");
      _logger.Debug("Debug");
      _logger.Info("Info");
      _logger.Warn("Warn");
      _logger.Error("Error");

      DI ILogger

      Přes DI si injecteme logger:

      private readonly ILogger _logger;
      
      public UserService(ILogger<UserService> logger)
      {
      
        _logger = logger;
      }

      Který pak používáme

      _logger.LogTrace("Trace");
      _logger.LogDebug("Debug");
      _logger.LogInformation("Info");
      _logger.LogWarning("Warn");
      _logger.LogError("Error");