paint-brush
Bilgisayar Monitörünüzü Ortam Monitörüne Dönüştürmek için Python ile Tersine Mühendislik LED Işıklarıile@reaminated
2,409 okumalar
2,409 okumalar

Bilgisayar Monitörünüzü Ortam Monitörüne Dönüştürmek için Python ile Tersine Mühendislik LED Işıkları

ile Reaminated12m2023/03/31
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Normal monitörünüzü, ışıkları ekranda o anda bulunan renklere uyacak şekilde değişen bir Ortam Monitörüne dönüştürün. Python ve RGB ışıklarının kullanıldığı bu eğitim, film ve oyun deneyiminizi nasıl geliştireceğinizi gösteren bir eğitimdir.
featured image - Bilgisayar Monitörünüzü Ortam Monitörüne Dönüştürmek için Python ile Tersine Mühendislik LED Işıkları
Reaminated HackerNoon profile picture
0-item

giriiş

Ambient TV'lere aşina olmayanlar için bu, daha sürükleyici bir deneyim sağlamak amacıyla TV ekranının kenarından ve yakın çevresinden atlamayı yumuşatmanın bir yoludur. Ortalıkta bazı LED ışıklar vardı ve ışıkları kodla kontrol etmenin mümkün olup olmadığını görmeye ve bilgisayar ekranımı bir ortam monitörü haline getirmeye karar verdim. Monitörüm için kullanmak istesem de, ışıklarınızın sahip olabileceği ses reaksiyonları veya rastgele desenler gibi diğer özellikler de dahil olmak üzere, gönderebileceğiniz her yerde ve hangi renklerle kullanılabilir. Daha önceki bir monitörde kullandığım için bu yazıyı bir süredir yazmayı planlıyordum, ancak yeni monitörüme eklemeyi bir türlü başaramadım, bu yüzden bu yazıyı bulabilecek herkes için ilerledikçe belgeledim. faydalıdır. O halde hadi konuya geçelim! (LED ışıkların muhtemelen Bluetooth Düşük Enerji (BLE) olacağını, dolayısıyla onlarla etkileşim kurabilmek için bilgisayarınızın BLE'yi desteklemesi gerektiğini lütfen unutmayın). Kodun tamamı GitHub'da .

Yüksek Düzey Adımlar

  • LED ışığının Bluetooth alıcısının hangi komutları kabul ettiğini öğrenin
  • Bilgisayarımın Bluetooth'u aracılığıyla LED ışıklara komutlar gönder
  • Geçerli ekranın baskın rengini elde edin
  • Baskın rengi LED ışıklara gönderin

Önkoşullar

  • Bluetooth destekli RGB LED ışıklar ve beraberindeki uygulama (Android kullanıyorum, iOS muhtemelen burada açıklanandan farklı bir yaklaşım gerektirecektir, ancak Bluetooth trafiğini izlemek için Wireshark'ı doğrudan kullanmak mümkün olmalıdır). Bu ışıkları monitörümün arkasına taktım
  • Wireshark
  • Android'in SDK araçları (özellikle adb.exe)
  • Geliştirici araçları (Python 3.10 kullanacağım, ancak herhangi bir 3.x sürümünün çalışması gerekir, ancak tercih ettiğiniz dil ne olursa olsun ilkeler aynı olmalıdır)
  • BLE komutlarının gönderileceği bir cihaz (örneğin, BLE'yi destekleyen bir dizüstü bilgisayar)


Bluetooth verilerini alma

Yapmamız gereken ilk adım, ışıklarla birlikte gelen uygulamanın beklendiği gibi çalıştığından emin olmaktır. Bu, ışığın orijinal uygulamasını çalıştırarak ve uygulamanızda bastığınız açma/kapama/aydınlatma düğmelerine bağlı olarak ışıkların buna göre tepki vermesini sağlayarak kolayca test edilebilir. Bunu yapıyoruz çünkü kısa bir süre sonra ışıkların üzerindeki Bluetooth alıcısına gönderilen belirli kodlara basıp tespit edeceğiz.


Benim uygulayabileceğim iki yaklaşım var. Bunlardan biri, uygulamanın JAR dosyasını kaynak koda dönüştürmek ve gönderilen kodları bulmaktı, ancak Bluetooth protokolü hakkında daha fazla bilgi edinmek istediğimden, tüm Bluetooth etkinliğini Android cihazıma kaydetmeyi ve oradan çıkarmayı seçtim. İşte nasıl:


  1. Android cihazınızda Geliştirici Seçeneklerini etkinleştirin.


  2. Bluetooth HCI gözetleme günlüğünü etkinleştirin (HCI, Ana Bilgisayar Denetleyici Arayüzü anlamına gelir). Bu seçeneği Ayarlar > Sistem > Geliştirici bölümünde bulabilir veya aşağıdaki görüntüdeki gibi ayarlarda arayabilirsiniz.


HCI Snoop Günlüklerini Etkinleştirme


  1. Artık her eylemin ışığın Bluetooth alıcısına ne gönderdiğini tanımlayabilmemiz için belirli eylemler gerçekleştirmemiz gerekiyor. Bu sırayla Açık/Kırmızı/Yeşil/Mavi/Kapalı olarak basit tutacağım, ancak ışıklarınız diğer özellikleri destekliyorsa, bunlarla da oynayabilirsiniz.


  2. Uygulamayı çalıştırın ve Açık, Kırmızı, Yeşil, Mavi ve Kapalı tuşlarına basın. Cihazınızda çok fazla Bluetooth etkinliği varsa filtrelemeyi kolaylaştırmak için yaklaşık süreye dikkat etmeniz de yararlı olabilir.


Gönderilecek Komutları Kaydetme


  1. Daha fazla gürültü duymamak için Bluetooth'u kapatın. Sonraki adımlarda Bluetooth komutlarını analiz edeceğiz ve bastığımız sırayı bildiğimiz için hangi tuşa bastığımıza hangi değerlerin karşılık geldiğini bulabiliriz.


  2. Artık telefondaki Bluetooth kayıtlarına erişmemiz gerekiyor. Bunu yapmanın birkaç yolu var, ancak bir hata raporu oluşturup dışa aktaracağım. Bunu yapmak için telefonun Ayarlar bölümünde USB Hata Ayıklamayı etkinleştirin, telefonu bilgisayara bağlayın ve adb.exe komut satırı aracını kullanın.


     adb bugreport led_bluetooth_report


  3. Bu, bilgisayarınızın yerel dizininde “ led_bluetooth_report.zip ” dosya adına sahip bir zip dosyası oluşturacaktır. İsterseniz bir yol belirleyebilirsiniz (örn. C:\MyPath\led_bluetooth_report")


  4. Bu zip'in içinde ihtiyacımız olan günlükler var. Bu, cihazdan cihaza değişiklik gösterebilir (cihazınızda başka bir yerde bulduysanız lütfen yorum yapın). Google Pixel telefonumda FS\data\misc\bluetooth\logs\btsnoop_hci.log konumundaydı


  5. Artık günlük dosyalarımız var, onları analiz edelim! Bunu yapmak için Wireshark kullanmaya karar verdim, bu yüzden Wireshark'ı başlatın ve Dosya...Aç... seçeneğine gidin ve btsnoop_hci günlük dosyasını seçin.


Her ne kadar göz korkutucu görünse de, Wireshark kaynak kodundaki Öznitelik Protokolü olan 0x0004 üzerindeki BTL2CAP'yi filtreleyerek aradığımız şeyi bulmamızı kolaylaştıralım. Öznitelik protokolü, iki BLE cihazının birbiriyle konuşma şeklini tanımlar; dolayısıyla uygulamanın ışıklarla nasıl konuştuğunu bulmamıza yardımcı olmak için ihtiyacımız olan şey budur. Wireshark'ta üst kısımdaki “ Ekran filtresi uygula ” çubuğuna btl2cap.cid == 0x0004 yazıp Enter tuşuna basarak logları filtreleyebilirsiniz.


Kolaylaştırmak için günlükleri filtreleyin


Artık günlüğü filtreledik; komutların aranmasını kolaylaştırmalıdır. Zaman damgalarına bakabiliriz (Yanlış formattaysa saati dönüştürmek için Görünüm…Saat Görüntüleme Formatı…Günün Saati seçeneğine gidin). Işıklara bir değer gönderdiğimiz kayıtlar olduğu için Gönderilen Yazma Komutu kayıtlarına bakmak istiyoruz. En son zamanınızın en altta olduğunu varsayarak son beş etkinliğe doğru ilerleyin. Bunlar sırasıyla Açık, Kırmızı, Yeşil, Mavi ve Kapalı olmalıdır; Kapalı sonuncu olmalıdır.


BS_ADDR ve Değerler - İhtiyacımız olan bilgiler!


Hedef BD_ADDR'yi not edin, çünkü buna kısa süre sonra ihtiyacımız olacak ve Sherlock Holmes şapkanızı takın, çünkü burası, renklerin ve açma/kapama komutlarının mesaj içinde nasıl kodlandığına ilişkin desenin kilidini açmamız gereken yerdir. Bu, ışık üreticisine bağlı olarak değişecektir ancak cihazım için aldığım değerlerin listesi:


  • Açık: 7e0404f00001ff00ef
  • Kırmızı: 7e070503ff000010ef
  • Yeşil: 7e07050300ff0010ef
  • Mavi: 7e0705030000ff10ef
  • Kapalı: 7e0404000000ff00ef


Bunlar açıkça onaltılık değerlerdir ve dikkatli bakarsanız bazı sabit kalıpların olduğunu görürsünüz. Desenleri bölelim, çünkü bu işleri daha net hale getirecektir.


  • Açık: 7e0404 f00001 ff00ef
  • Kırmızı: 7e070503 ff0000 10ef
  • Yeşil: 7e070503 00ff00 10ef
  • Mavi: 7e070503 0000ff 10ef
  • Kapalı: 7e0404 000000 ff00ef


Saf kırmızı, yeşil ve mavinin onaltılık değerlerine aşina olanlar için değerlerin sırasıyla #FF000, #00FF00 ve #0000FF olduğunu bileceksiniz; bu da tam olarak yukarıda görebildiğimiz gibi. Bu, artık renkleri istediğimiz şekilde değiştirecek formatı bildiğimiz anlamına geliyor! (veya en azından ışıkların kendilerinin neler yapabileceğine göre). Açık ve Kapalı'nın renklerden farklı bir formata sahip olduğunu ve birbirine benzer olduğunu da görebiliriz; Açık'ta f00001 ve Kapalı'da 00000 bulunur.

Bu kadar! Artık kodlamaya ve ışıklarla etkileşime geçmeye başlamak için yeterli bilgiye sahibiz.

LED ışıklara bağlanma

İhtiyacımız olan üç temel şey var:


  • Cihazın adresi (yukarıdaki Hedef BD_ADDR'dir)

  • Cihaza gönderilecek değerler (yukarıda elde edilen onaltılık değerler)

  • Değiştirmek istediğimiz özellik. Bluetooth LE özelliği, esas olarak bir ana bilgisayar ile istemci Bluetooth aygıtları arasında gönderilebilecek verileri tanımlayan bir veri yapısıdır. Işıkları ifade eden karakteristiği (16 bit veya 128 bit UUID) bulmamız gerekiyor. Burada bulunabilecek bazı yaygın olarak kullanılan atanmış numaralar vardır ancak cihaz bunlara uymuyorsa özel bir UUID kullanıyor olabilirler. Işıklarım atanan numaralar listesinde olmadığından kodla bulalım.


Python 3.10 ve Kasvetli 0.20.1 kullanıyorum. Bilgisayarınızdaki Bluetooth'un açık olduğundan emin olun (cihazla eşleştirmenize gerek yoktur, kod aracılığıyla ona bağlanacağız).


 # Function to create a BleakClient and connect it to the address of the light's Bluetooth reciever async def init_client(address: str) -> BleakClient: client = BleakClient(address) print("Connecting") await client.connect() print(f"Connected to {address}") return client # Function we can call to make sure we disconnect properly otherwise there could be caching and other issues if you disconnect and reconnect quickly async def disconnect_client(client: Optional[BleakClient] = None) -> None: if client is not None : print("Disconnecting") if characteristic_uuid is not None: print(f"charUUID: {characteristic_uuid}") await toggle_off(client, characteristic_uuid) await client.disconnect() print("Client Disconnected") print("Exited") # Get the characteristic UUID of the lights. You don't need to run this every time async def get_characteristics(client: BleakClient) -> None: # Get all the services the device (lights in this case) services = await client.get_services() # Iterate the services. Each service will have characteristics for service in services: # Iterate and subsequently print the characteristic UUID for characteristic in service.characteristics: print(f"Characteristic: {characteristic.uuid}") print("Please test these characteristics to identify the correct one") await disconnect_client(client)


Kod hakkında yorum yaptım, bu yüzden kendini açıklayıcı olmalı ama esasen ışıklara bağlanıyoruz ve ortaya çıkardığı tüm özellikleri buluyoruz. Çıktım şuydu:


Karakteristik: 00002a00-0000-1000-8000-00805f9b34fb Karakteristik: 00002a01-0000-1000-8000-00805f9b34fb Karakteristik: 0000fff3-0000-1000-8000-00805f9b34fb Karakteristik: 0000fff4-0000-1000-8000-00805f9b34fb


İlk iki UUID'nin hızlı bir Google'ı, bunun bizim için alakasız olan hizmetin adı ve görünümüne atıfta bulunduğunu gösterir. Bununla birlikte, bu sayfaya göre üçüncü ( 0000fff3-0000-1000-8000-00805f9b34fb ) yazma özelliği olduğundan üçüncü ve dördüncü en uygunu gibi görünmektedir . Mükemmel, artık bu özel cihazın bir değerle (onaltılık renk) yazması için ihtiyacımız olan özelliğe sahibiz.

LED ışıkların kontrol edilmesi

Sonunda ihtiyacımız olan tüm parçalara sahibiz. Bu aşamada hangi renk girişini kullanmak istediğiniz konusunda yaratıcı olabilirsiniz. Örneğin, portföyünüzün performansına göre renkleri değiştirmek için ışıkları bir ticaret piyasası API'sine bağlayabilirsiniz. Bu durumda, monitörlerimizi ortama duyarlı hale getirmek istiyoruz, bu nedenle ekranın baskın rengini elde edip bunu göndermemiz gerekiyor.


Bunu yapmanın birçok yolu vardır, bu nedenle istediğiniz algoritmaları denemekten çekinmeyin. En basit yaklaşımlardan biri, ekrandaki her X piksel sayısını yinelemek ve ortalamayı almak olacaktır; daha karmaşık çözümler ise insan gözünün algıladığı renkleri daha baskın olarak arar. Paylaşmak istediğiniz bulgular hakkında yorum yapmaktan çekinmeyin!

Bu blog yazısının hatırı için, fast_colorthief kütüphanesinin get_dominant_color yöntemini kullanarak konuyu basit tutacağım.


 ''' Instead of taking the whole screensize into account, I'm going to take a 640x480 resolution from the middle. This should make it faster but you can toy around depending on what works for you. You may, for example, want to take the outer edge colours instead so it the ambience blends to the outer edges and not the main screen colour ''' screen_width, screen_height = ImageGrab.grab().size #get the overall resolution size region_width = 640 region_height = 480 region_left = (screen_width - region_width) // 2 region_top = (screen_height - region_height) // 2 screen_region = (region_left, region_top, region_left + region_width, region_top + region_height) screenshot_memory = io.BytesIO(b"") # Method to get the dominant colour on screen. You can change this method to return whatever colour you like def get_dominant_colour() -> str: # Take a screenshot of the region specified earlier screenshot = ImageGrab.grab(screen_region) ''' The fast_colorthief library doesn't work directly with PIL images but we can use an in memory buffer (BytesIO) to store the picture This saves us writing then reading from the disk which is costly ''' # Save screenshot region to in-memory bytes buffer (instead of to disk) # Seeking and truncating fo performance rather than using "with" and creating/closing BytesIO object screenshot_memory.seek(0) screenshot_memory.truncate(0) screenshot.save(screenshot_memory, "PNG") # Get the dominant colour dominant_color = fast_colorthief.get_dominant_color(screenshot_memory, quality=1) # Return the colour in the form of hex (without the # prefix as our Bluetooth device doesn't use it) return '{:02x}{:02x}{:02x}'.format(*dominant_color)


Kod yorumlanmıştır, dolayısıyla ne olduğu açık olmalıdır, ancak ekranın ortasından daha küçük bir bölgeyi alıyoruz ve ardından o bölgeden baskın rengi alıyoruz. Daha küçük bir bölgeyi almamın nedeni performanstır; daha az pikselin analiz edilmesi gerekir.


Neredeyse geldik! Artık ne göndereceğimizi, nereye göndereceğimizi biliyoruz. Bu mücadelenin son büyük kısmı olan onu gerçekten göndermek olan bitirelim. Neyse ki, Bleak kütüphanesinde bu oldukça basittir.


 async def send_colour_to_device(client: BleakClient, uuid: str, value: str) -> None: #write to the characteristic we found, in the format that was obtained from the Bluetooth logs await client.write_gatt_char(uuid, bytes.fromhex(f"7e070503{value}10ef")) async def toggle_on(client: BleakClient, uuid: str) -> None: await client.write_gatt_char(uuid, bytes.fromhex(ON_HEX)) print("Turned on") async def toggle_off(client: BleakClient, uuid: str) -> None: await client.write_gatt_char(uuid, bytes.fromhex(OFF_HEX)) print("Turned off")


Günlüklerden öğrendiğimiz gibi, her rengin sabit bir şablonu vardır, bu nedenle ortak kısmı sabit kodlamak için f dizelerini kullanabiliriz ve ortadaki değer için basitçe bir rengin onaltılı sayısını iletebiliriz. Bu bizim döngümüzden çağrılabilir. Açık ve Kapalı'nın benzersiz onaltılık değerleri vardı, bu yüzden ayrı ayrı işlevler oluşturdum ve ilgili onaltılığı içeren sabit bir değer aktardım.


 while True: # send the dominant colour to the device await send_colour_to_device(client, characteristic_uuid, get_dominant_colour()) # allow a small amount of time before update time.sleep(0.1)


Ve işte elimizde; Bluetooth LED ışıklarımız artık ekrandaki renklerle kontrol ediliyor ve kendi Ortam Monitörümüzü oluşturuyor.


Bu yazıya özel olmayan az miktarda altyapı kodu içeren kodun tamamını GitHub'da görebilirsiniz. Kodu kendi kendini açıklayıcı olacak şekilde yorumlamaya çalıştım ancak herhangi bir soru sormaktan veya öneride bulunmaktan çekinmeyin.


Umarız bu size LED ışıklarınızla nasıl yaratıcı olmaya başlayabileceğiniz konusunda bir fikir verir.

Gelecekteki İyileştirmeler

  • Çok renkli - Işık şeritlerimin aynı anda yalnızca bir rengi olabilir, ancak her biri kendi rengine sahip dört çeyreğe sahip olabilen başka bir setim var. Bu, daha doğru bir ortam ayarı sağlayacak şekilde monitörün bölümlerinin ekrandaki dört bölümle eşleşmesinin mümkün olabileceği anlamına gelir. Bu ışıklar Bluetooth yerine Wifi üzerinden çalışıyor ve gelecekteki bir proje olabilir.
  • Parlaklık – basitleştirmek için sadece renk değişimine ve açma-kapama komutlarına baktım. Ancak bu, parlaklık kontrol komutlarının algılanıp renk algoritmasına atılmasıyla kolayca iyileştirilebilir.
  • Performans - Işıkların gerçek zamanlı olarak değişmesini istediğimiz için performans kritik öneme sahiptir. Özellikle insanlar tarafından algılandığında hangi rengin en baskın olarak değerlendirileceğini tespit etmek için bazı karmaşık algoritmalar vardır (bu da tüm renk dönüşümlerine yol açar). Ancak bunun oldukça hızlı çalışması gerektiğinden performans ve doğruluk arasında bir denge olması gerekir. Gelecekteki bir gelişme, ekrandaki pikselleri doğrudan analiz etmek yerine, arabellekten okumak için doğrudan grafik kartına erişmeyi denemek olabilir. Eğer bu mümkünse, ışıkların tepkisini optimize edebilecek şekilde grafik arabelleğinden ekrana kadar geçen süreyi de ortadan kaldırmış olursunuz.


Herhangi bir geri bildiriminiz veya sorunuz varsa aşağıya yorum yapmaktan çekinmeyin.


Burada Ayrıca Yayınlandı