Skocz do zawartości

Gieneq

Moderator
  • Zawartość

    3 674
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    184

Gieneq zajął 1. miejsce w rankingu.
Data osiągnięcia: 26 stycznia.

Treści użytkownika Gieneq zdobyły tego dnia najwięcej polubień!

9 obserwujących

O Gieneq

  • Urodziny 19.05.1994

Informacje

  • Płeć
    Mężczyzna
  • Lokalizacja
    Gdynia
  • Programuję w
    Python
  • Zawód
    Grafik komputerowy
  • Moje zainteresowania:
    Malowanie obrazów (akwarele, oleje), elektronika, programowanie

Ostatnio na profilu byli

Blok z ostatnio odwiedzającymi jest wyłączony i nie jest wyświetlany innym użytkownikom.

Osiągnięcia użytkownika Gieneq

Lokalny weteran

Lokalny weteran (17/19)

  • Odkrywca (podanie odp. na własne pytanie)
  • Za 25 postów
  • Za 5 postów
  • Za 100 postów
  • Za 1 tys. postów

Odznaki

2,1 tys.

Reputacja

  1. @DeMax Cześć 🙂 Super, życzę powodzenia!
  2. @Lucasyno wymagałoby to głębszej analizy albo symulacji. Może znaczenie ma, że teraz mała rezystacja występuje przy dodatnim napięciu. Może wypowie się ktoś z większym doświadczeniem.
  3. @Fugio witam Macieju na naszym forum 🙂 fajnie, że rozwijasz swoje zainteresowania. Powodzenia!
  4. @DeadGeneratio podlinkuję swój projekt 🙂
  5. @Harnas certifikat mam z takiego polecenia: echo "" | openssl s_client -showcerts -connect XXXX.azure-devices.net:8883 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >hub.pem Próbowałem po SSL/TLS i Websocket Secure i podobne zachowanie. Ale udało się na nowo połączyć. Pomyślałem że może być jakiś timeout i w ustawieniach clienta MQTT zmieniałem wartości: mqtt_cfg.network.timeout_ms = 10000; mqtt_cfg.network.reconnect_timeout_ms = 10000; mqtt_cfg.network.disable_auto_reconnect = false; // mqtt_cfg.network.refresh_connection_after_ms = 25000; i zauważyłem, że problem nie pojawia się, jak mam refresh w sensowym czasie. Stąd teoria: urządzenie powinno podłączyć się, wysłać i rozłączyć. Ciekawe że po tym jak udało się podłączyć, wróciłem do poprzedniego kodu który nie działał i znowu się naprawił. Czyli problem jest gdzieś przy serwerze. Może faktycznie serwer odrzuca urządzenia które za długo lub zbyt często coś robią.
  6. A zapytam, siedzę nad tym już za długo. W Azurze jest DPS i IoT HUB. DPS służy do rejestracji urządzeń. IoT HUB do komunikacji. Oba mają opcję SDK, którego nie chcę używać bo to jakiś bałagan. Można komunikować się po MQTT 3.1.1 i TLS/SSL lub Websocket. Z DPSem nie mam żadnych problemów. Ale z IoT HUBem cały czas. Wyjdę od tego że mam referencyjny kod w Pythonie na Desktopa który działa zawsze. def setup_mqtt_client(device_id, hub_name, sas_token): """Setup and return an MQTT client.""" client = mqtt.Client(client_id=device_id, protocol=mqtt.MQTTv311) print("mqtt_client_id:", device_id) client.username_pw_set(username=f"{hub_name}/{device_id}/?api-version=2018-06-30", password=sas_token) print("mqtt_username:", f"{hub_name}/{device_id}/?api-version=2018-06-30") print("mqtt_password:", sas_token) client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2) client.tls_insecure_set(False) def on_connect(client, userdata, flags, rc): print(f"Connected with result code {rc}") def on_publish(client, userdata, mid): print(f"Message Published: {mid}") client.on_connect = on_connect client.on_publish = on_publish return client mqtt_client.connect(iothub_hostname, MQTT_BROKER_PORT, 60) mqtt_client.loop_start() mqtt_client.publish(f"devices/{DEVICE_ID}/messages/events/", "HACK HACK HACK") W minimalnym przykładzie C ESP-IDF biorę dane logowania: device_id, username i hasło i podkładam do przykłądu MQTT/SSL. Kod działał przez jakiś czas. Po przerwie kilku tygodni już nie działał. Kilak restartów i zaczął. Restart i już nigdy nie zaczął z powrotem. const esp_mqtt_client_config_t mqtt_cfg = { .broker = { .address.uri = CONFIG_BROKER_URI, .verification.certificate = (const char *)broker_pem_start, }, .session = { .keepalive = 240, .protocol_ver = MQTT_PROTOCOL_V_3_1_1 }, .credentials = { .client_id = "theendisreal_1", .username = "XXXXXXXXXXX.azure-devices.net/theendisreal_1/?api-version=2018-06-30", .authentication.password = "SharedAccessSignature sr=XXXXXXXXXXX.azure-devices.net%2Fdevices%2Ftheendisreal_1&sig=ZZZZZZZZZZZZZZZZ&se=1709043213" } }; Tu jest log: I (6413) MQTTS_EXAMPLE: Other event id:7 I (7293) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED I (7293) MQTTS_EXAMPLE: sent subscribe successful, msg_id=45317 I (7293) MQTTS_EXAMPLE: sent subscribe successful, msg_id=37869 I (7293) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=20820 I (7323) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=45317 I (7323) MQTTS_EXAMPLE: sent publish successful, msg_id=0 I (7363) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=37869 I (7363) MQTTS_EXAMPLE: sent publish successful, msg_id=0 I (7363) MQTTS_EXAMPLE: MQTT_EVENT_UNSUBSCRIBED, msg_id=20820 E (12513) esp-tls-mbedtls: read error :-0x004C: E (12513) transport_base: esp_tls_conn_read error, errno=Socket is not connected E (12513) mqtt_client: esp_mqtt_handle_transport_read_error: transport_read() error: errno=128 I (12523) MQTTS_EXAMPLE: MQTT_EVENT_ERROR I (12523) MQTTS_EXAMPLE: Last error code reported from esp-tls: 0x0 I (12533) MQTTS_EXAMPLE: Last tls stack error number: 0x4c I (12543) MQTTS_EXAMPLE: Last captured errno : 0 (Success) E (12543) mqtt_client: mqtt_process_receive: mqtt_message_receive() returned -1 I (12553) MQTTS_EXAMPLE: MQTT_EVENT_DISCONNECTED Hasło jest generowane z SAS tokenu, ten ma ograniczenie czasowe. Sprawdzałem i błąd jest inny gdy poda się przedawnione hasło. Podanie błędnego certyfikatu to też inny błąd. /* This will show if password (sas token) is autdated */ I (6413) MQTTS_EXAMPLE: Other event id:7 W (7383) mqtt_client: Connection refused, not authorized I (7383) MQTTS_EXAMPLE: MQTT_EVENT_ERROR I (7383) MQTTS_EXAMPLE: Connection refused error: 0x5 E (7383) mqtt_client: MQTT connect failed I (7393) MQTTS_EXAMPLE: MQTT_EVENT_DISCONNECTED /* This will show if pem file is not for this hostname*/ I (6413) MQTTS_EXAMPLE: Other event id:7 E (6603) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x2700 I (6603) esp-tls-mbedtls: Failed to verify peer certificate! E (6613) esp-tls: Failed to open new connection E (6613) transport_base: Failed to open a new connection E (6623) mqtt_client: Error transport connect I (6623) MQTTS_EXAMPLE: MQTT_EVENT_ERROR Mamy wykupionego IoT HUBa, jakiś niski tier. Ma ktoś pomysł na to?
  7. @ethanak pewnie że tak można, to super metoda. Niedawno pisałem taki program w pracy. Ale jakoś na DIY nie chciało się przenosić 😅
  8. Ramka od ponad miesiąca jest już gotowa, ale jakoś zapomniałem wrzucić aktualizację - można wrzucać własne zdjęcia, które po przesłaniu zapisywane są w pamięci nieulotnej jako plik PNG. Zastanawiałem się czy lepiej jest łączyć takie urządzenie z siecią domową czy korzystać jako access point. Dla urządzenia, które stoi na miejscu raczej lepsza jest pierwsza opcja, ale w tym przypadku zostanie jako access point. Film demonstrujący działanie:
  9. @Dirichleta cześć 1) 2) Finalny plik elf musi się skompilować, ale masz i tak mechanizm ograniczania kompilacji poszczególnych plików przed wejściem do linkera. Eclipse sprawdza powiązania pomiędzy plikami i kompiluje tylko to do których doszła zmiana. Możesz w jakiś sposób spróbować wymusić kompilację od zera to zobaczysz dużą różnicę w czasie kompilacji.
  10. Gieneq

    Kariera w embedded

    @n1k0 jak na pracę hybrydową, co raczej będzie częściej, to zależy czy w okolicy jest trochę firm produkcyjnych. Np na pomorzu to nie takie oczywiste. Ale z ciekawostek kiedyś aplikowałem do jednego corpo na programitę 100% zdalnie C++ w technologiach radiowych. Nie miałem wtedy żadnego doświadczenia za wyjątkiem hobbystycznych zabaw różnymi językami: GPU, gamedev, web i embedded. Pytania techniczne były proste, takie że chyba szło się domyśleć. Coś tam z mechanizmów wielowątkowości i proste pytanie ze wskaźników C. Stawka 14k brutto 😅 Zrezygnowałem, bo było coś innego. Równolegle praca w Pythonie, gdzieś obok Machine Learning. Pytania kosmiczne, live coding na 1.5h, nic z tego. Aplikowałem na juniora 6k brutto. Teraz pracuję w firmie, która nie zadawała żadnych pytań 😅 ale jest fajnie. Z rozmów z różnymi ludźmi wynika że jakieś Pythony, JSy itp mają bardzo mały próg wejścia i stosunkowo duże perspektywy, dlatego pcha się tam masa ludzi. Na jednej rozmowie, gość mówił że nie mam co pchać się w te tematy bo na moje miejsce jest 100 ludzi co chociaż skończyli kurs Machine Learning. Ale wracając, w embedded jesteś po lepszej stronie - niszowy temat, specyficzne wymagania, najmniejsze stawki w IT -> mniej chętnych. Jak jeszcze zgodzisz się na pracę hybrydową to biorą od razu. W praktyce możesz iść tak jak stoisz, jak pokażesz że znasz się na temacie, wiesz co się dzieje w projekcie to będzie ok. Później jednak praca to weryfikuje, ale posiedzisz rok w firmie będziesz się uczył 8h + powiedzmy 3h w domu i po roku będziesz już bardziej wiedział gdzie siedzisz
  11. Gieneq

    Kariera w embedded

    @n1k0 to co pisze @Treker jak najbardziej, sam zaczynałem od takiego kursu i pracuję jako programista embedded w STMach. W mikrokontrolerach jest sporo pracy w STMach i Espressifie i szukaj czegoś bardziej w RTOSie, np FreeRTOS, Azure RTOS, Zephyr. Bare metal raczej nie jest do zarabiania pieniędzy, choć ćwiczysz w tym pisanie driverów do układów peryferyjnych, które później są używane w procesach RTOSa. Jak chcesz pracę zdalną to może być trudne, lepiej szukać czegoś w embedded linux. W IoT jest też sporo pracy, wymaga to znajomości technologii sieciowych. Z aspektów miekkich trzeba mieć dużo chęci, woli walki - jak trafiasz na wadliwy sprzęt i musisz dojść dlaczego nie działa, później męczyć się z do połowy działającym układem aż przyjdzie kolejny prototyp, który może mieć inne problemy. Kolega automatyk jak patrzy na naszą pracę tylko utwierdza się w przekonaniu że dobrze że nie robi tego co my. Ale praca ta ma też sporo plusów, na pewno jest ciekawa.
  12. Jest dalszy progres w tym temacie. Z pomocą chata GPT dodałem algorytm ditheringu Floyd-Steinberg. Działa podgląd, obrót obrazka, kursorem myszy można przesunąć obrazek a suwakiem przeskalować. Gamma do ewentualnej poprawy szczegółów. 2 przyciski: po prawej pobiera plik PNG na urządzenie. po lewej gdy strona jest w trybie deweloperskim pobiera plik BMP 1bit per pixel, gdy jest shosytowana zamienia binarkę na stringa i wysyła na endpoint z metodą POST. Pliki BMP składam generując nagłówek i dodając binarkę na końcu: function createBMP(monochromeData, width, height) { const datalen = monochromeData.length; const fileSize = 62 + datalen; const header = new Uint8Array([ /*00*/ 0x42, 0x4D, // BM /*02*/ fileSize & 0xff, (fileSize >> 8) & 0xff, (fileSize >> 16) & 0xff, (fileSize >> 24) & 0xff, /*06*/ 0x00, 0x00, 0x00, 0x00, // Reserved /*0a*/ 0x3e, 0x00, 0x00, 0x00, // Offset to pixel data /*0e*/ 0x28, 0x00, 0x00, 0x00, // Info Header size /*12*/ width & 0xff, (width >> 8) & 0xff, 0x00, 0x00, // Width /*16*/ height & 0xff, (height >> 8) & 0xff, 0x00, 0x00, // Height /*1a*/ 0x01, 0x00, // Planes /*1c*/ 0x01, 0x00, // Bits per pixel (1-bit) /*1e*/ 0x00, 0x00, 0x00, 0x00, // Compression /*22*/ datalen & 0xff, (datalen >> 8) & 0xff, (datalen >> 16) & 0xff, (datalen >> 24) & 0xff, // Image size /*--*/ 0x00, 0x00, 0x00, 0x00, // X pixels per meter /*--*/ 0x00, 0x00, 0x00, 0x00, // Y pixels per meter /*--*/ 0x00, 0x00, 0x00, 0x00, /*--*/ 0x00, 0x00, 0x00, 0x00, /*--*/ 0x00, 0x00, 0x00, 0x00, /*3a*/ 0xff, 0xff, 0xff, 0x00, ]); const bmpData = new Uint8Array(header.length + monochromeData.length); bmpData.set(header, 0); bmpData.set(monochromeData, header.length); return bmpData; } Ramka narazie odczytuje pliki BMP z pamięci, ale to nie problem dodać partycję i zapisywać tam pobrane BMPy. Kod strony z obrazkami na ikony itp liczy z 25kB, gdyby zminimalizować treść to będzie jeszcze lepiej. Działą ogólnie sprawnie. Na desktopie wygląa ok, ale na smartphonie tak sobie. Później się z tym uporam, ale to może umiesczę w osobnym temacie DIY.
  13. Proof of concept jest 😄 Skorzystałem z przykładu esp-idf/protocols/http_server/simple i file_server. Z file_server można dojść w jaki sposób wystawić endpoint z plikiem np najprostszy favico.ico czyli ikonka w zakładce. Jest to bardzo proste: static esp_err_t favicon_get_handler(httpd_req_t *req) { extern const unsigned char favicon_ico_start[] asm("_binary_favicon_ico_start"); extern const unsigned char favicon_ico_end[] asm("_binary_favicon_ico_end"); const size_t favicon_ico_size = (favicon_ico_end - favicon_ico_start); httpd_resp_set_type(req, "image/x-icon"); httpd_resp_send(req, (const char *)favicon_ico_start, favicon_ico_size); ESP_LOGW(TAG, ">> Got favicon.ico [%uB]", favicon_ico_size); return ESP_OK; } static const httpd_uri_t favicon = { .uri = "/favicon.ico", .method = HTTP_GET, .handler = favicon_get_handler, .user_ctx = NULL }; Trzeba to jeszcze zarejestrować: if (httpd_start(&server, &config) == ESP_OK) { // Set URI handlers ESP_LOGI(TAG, "Registering URI handlers"); httpd_register_uri_handler(server, &hello); httpd_register_uri_handler(server, &echo); httpd_register_uri_handler(server, &ctrl); httpd_register_uri_handler(server, &favicon); httpd_register_uri_handler(server, &main_index); httpd_register_uri_handler(server, &main_script); httpd_register_uri_handler(server, &main_styles); return server; } W podobny sposób client będzie dopytywał się o pliki html, js, css więc dla nich też robię podobne endpointy. Pliki są zaciągane tak samo, dodając je w CMakeLists.txt: idf_component_register(SRCS "main.c" INCLUDE_DIRS "." EMBED_FILES "favicon.ico" "index.html" "script.js" "styles.css" REQUIRES ${requires}) Dalej zostaje napisanie kodu strony - ten można przetestować poza ESP. Wspomniana biblioteka niezabardzo działa, jest tam problem z jakimś "CORS" - nie wnikam co to, jak będzie trzeba to się nad tym pochylę. Na jakimś stacku znalazłem coś lepszego - przykład jak wciągnąć obrazek z pliku, zmodyfikować go, narysować na canvasie i pobrać. Pozostało dodać własny algorytm i zamiast pobierania wrzucić na endpoint. Z wysłaniem na endpoint też prosta sprawa - jest do tego funkcja pobierająca treść body, która buforem pobiera aż do końca. Tu przykład dla endpointa z metodą POST: char buf[100]; int ret, remaining = req->content_len; while (remaining > 0) { /* Read the data for the request */ if ((ret = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)))) <= 0) { if (ret == HTTPD_SOCK_ERR_TIMEOUT) { /* Retry receiving if timeout occurred */ continue; } return ESP_FAIL; } /* Send back the same data */ httpd_resp_send_chunk(req, buf, ret); remaining -= ret; /* Log data received */ ESP_LOGI(TAG, "=========== RECEIVED DATA =========="); ESP_LOGI(TAG, "%.*s", ret, buf); ESP_LOGI(TAG, "===================================="); } Jak widać POST do endpointa /echo działa: I (636201) example: =========== RECEIVED DATA ========== I (636201) example: Tu bedzie obrazek I (636201) example: ==================================== Dorzucam jeszcze ten wstępny kod strony: <!DOCTYPE html> <html lang="pl"> <head> <meta charset="UTF-8"> <title>Imagesadsfdgfdsa Upload and Trim</title> <link rel="stylesheet" href="styles.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="ditherjs.dist.js"></script> </head> <body> <p> Frame image uploader </p> <input type="file" id="imageInput"> <canvas id="canvas"></canvas> <button onClick="brightness(1.5)">Lighter</button> <button onClick="brightness(0.5)">Darker</button> <button onClick="save()">Save</button> <script src="script.js"></script> </body> </html> CSS pominę - nic ciekawego, ale JS może się komuś przyda: const imageInput = document.getElementById('imageInput'); const canvas = document.getElementById('canvas'); context = canvas.getContext('2d'); imageInput.addEventListener('change', function(event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { const img = new Image(); img.src = e.target.result; img.onload = function() { context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(img, 0, 0, canvas.width, canvas.height); }; }; } }); function saveCanvasAsImage(canvas, filename) { const dataURL = canvas.toDataURL('image/png'); const link = document.createElement('a'); link.href = dataURL; link.download = filename || 'canvas-image.png'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } const img = new Image(); img.src = `data:image/jpeg;base64,${getImageFromDb()}`; img.onload = () => { canvas.width = img.width; canvas.height = img.height; const imgX = canvas.width/2 - img.width/2; const imgY = canvas.height/2 - img.height/2; context.drawImage(img, imgX, imgY); } function brightness(multiplier) { const imgX = canvas.width/2 - img.width/2; const imgY = canvas.height/2 - img.height/2; const imageData = context.getImageData(imgX, imgY, img.width, img.height); const dataArray = imageData.data; for(let i = 0; i < dataArray.length; i += 4){ var red = dataArray[i]; var green = dataArray[i + 1]; var blue = dataArray[i + 2]; dataArray[i] = multiplier * red; dataArray[i + 1] = multiplier * green; dataArray[i + 2] = multiplier * blue; } context.putImageData(imageData, imgX, imgY); }; function save() { const dataURL = canvas.toDataURL().replace('data:', '').replace(/^.+,/, ''); console.log(dataURL); saveCanvasAsImage(canvas, 'my-image.png'); } function getImageFromDb() { return "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"; } Autor wpisu postanowił dać zakodowany obrazek prosto w kodzie funkcji 😄
  14. @Kacper_01 Witam na forum 🙂 Fajnie że tu trafiłeś @MarekM Cześć! @kmiew1 Witam Wiesławie na naszym forum 🙂 dziękujemy za pozytywny komentarz, życzę powodzenia z radzeniem sobie z zadaniami. @StefekKato witam serdecznie 🙂 Super! Nie trać zapału, elektronika to świetne zajęcie @programator5 witam serdecznie na forum 🙂 zachęcam do dalszej aktywności @AntekMontaz witam serdecznie 🙂 @MariuszM71 również witam serdecznie 🙂 @Okotymek cześć Tymon, fajnie że zaczynasz w tak młodym wieku 🙂 tak trzymaj! @burczymucha witam serdecznie 🙂 To świetnie! Trzeba szukać nowych wyzwań. Tu nie brakuje ludzi co ciągle coś robią. Powodzenia!
  15. Zaskoczyłeś mnie, OpenCV jest w JS. Ale to chyba za dużo, tu jest coś tylko do tego https://github.com/danielepiccone/ditherjs Ale w tym momencie bardziej nie rozumiem tych spraw webowych. Jak sobie wyobrazić że użytkownik wybiera obrazek ze swojego systemu plików, to się robi w przegląarce wykonującej JS i na koniec skąś bierze się plik obrazka .BMP który trafia na serwer.
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.