Skip to content

Nokia routerlarda toplu SDP oluşturma

nokia routerlarda toplu olarak sdp oluşturma ihtiyacı olurşursa aşağıdaki formatta bir excel dosyası oluşturup

sdpid routera routerb routerbip
10093 router_a routerb_b 10.10.10.1
4806 router_a routerb_d 10.10.10.3
1078 router_a routerb_f 10.10.10.5

aşagıdaki python kodu kullanarak oluşturduğumuz jinja formatına uygun kodları üretebiliriz… oluşturulacak routerda sdpid nin var olmaması gerekmektedir.

import pandas as pd
from jinja2 import Environment, FileSystemLoader

# Excel dosyasını oku
df = pd.read_excel('sdp_create.xlsx')

# Jinja2 ortamını ayarla (şablon dosyası ile aynı dizinde çalıştığını varsayıyoruz)
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('sdp_create_template.j2')

# Excel'den okunan veriyi listeye çevir
data = df.to_dict(orient='records')

# Jinja2 ile konfigürasyon dosyasını oluştur
output = template.render(items=data)

# Sonucu dosyaya yaz
with open('sdp_create_config.txt', 'w', encoding='utf-8') as f:
    f.write(output)

sdp_create_template.j2 dosyasında sdp mpls olarak oluşturulup ldp yi aktif ettiğimiz bir örnek var.

{% for item in items %}
/configure service sdp {{ item.sdpid }}  mpls create
info
description "to_{{ item.routerb }} "
far-end {{ item.routerbip }} 
ldp
path-mtu 2000
keep-alive
    shutdown
exit
no shutdown

{% endfor %}

https://github.com/ferhatcicek/ferhatcicek.com/tree/main/nokia%20routerlarda%20toplu%20sdp%20olusturma adresinden kodlara ve örnek excel dosyasına erişebilirsiniz

m-lab speedtest hız verilerine erişim

NDT, Measurement Lab (M‑Lab) tarafından geliştirilen açık kaynaklı bir ağ performans testi aracıdır; upload, download ve gecikme gibi parametreleri ölçer
M‑Lab NDT verileri açık şekilde Google Cloud Storage ve BigQuery üzerinden erişilebilir hâldedir..
Kullanılan M-Lab’in https://speed.measurementlab.net adresinden test yapabilmektedir.

Test sonuçlarının Türkiye verilerini incelemek amacıyla Google Cloud Console üzerinden veri çekmeye yönelik bir kod geliştirme ihtiyacı doğmuştur. Mevcut yöntemlerle veri alımı mümkün olsa da, Türkiye’de M-Lab servisi yaygın olarak kullanılmadığı için elde edilen veri setleri sınırlı ve temsil edici olmamaktadır.

nokia routerda vpls servis altındaki sapların silinmesi

nokia routerda belirli bir servis altındaki sapları silme ihtiyacı durumunda aşagıdaki kod kulllanılabilir.

import pandas as pd
from jinja2 import Environment, FileSystemLoader

# Excel dosyasını oku
df = pd.read_excel('sap_delete.xlsx')

# Jinja2 ortamını ayarla (şablon dosyası ile aynı dizinde çalıştığını varsayıyoruz)
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('sap_delete_template.j2')

# Excel'den okunan veriyi listeye çevir
data = df.to_dict(orient='records')

# Jinja2 ile konfigürasyon dosyasını oluştur
output = template.render(items=data)

# Sonucu dosyaya yaz
with open('sap_delete_config.txt', 'w', encoding='utf-8') as f:
    f.write(output)

üretilecek komut için aşagıdaki jinja template ini kullanyoruz..

{% for item in items %}
/configure service vpls {{ item.SvcId }} sap {{ item.PortId }} shutdown
/configure service vpls {{ item.SvcId }} no sap {{ item.PortId }} 
{% endfor %}

sap_delete_config.txt dosyasında tempalte sonucuna uygun konfigürasyon oluşmuş olacaktır..

kullanacağımız excel ise show service sap-using komutunun çıktısına uygun olarak aşagıdaki formatta olmaldıır..

PortIdSvcIdIngressIng.EgressEgr.AdmOpr
lag-40:1011.0123454none45noneUpDown
lag-42:1011.0123454none45noneUpDown
lag-44:1011.0123454none45noneUpDown

Gerekli kodları aşagdaıki github adresinden ulaşılabilir.

https://github.com/ferhatcicek/nokia-service-sap-delete

ookla speedtest verisini indirme ve analiz etmek

5g olaylarından dolayı hız testleri gündemde. bilinen ve doğru sonuç veren çok fazla hız testi sayfası yok. neredeyse hiç birinin açık verisi bulunmuyor. ookla nın çeyrek halinde yayınlandığı veriler bulunuyor ancak bu veriler çok kısıtlı.. örnek olarak operatör bilgisi bulunmuyor. bilr bölge için genel hız testi sonuçlarını incelemeye yardımcı olabiliryor.. açık veriler yılın çevrekleri şeklinde yayınlanıyor.

dosyalar belirli bir yapıya göre yayınlanıyor. en son yayınlanan çevrek verilerine göre türkiye verilerini indirecek bir python kod yazalım. verilerde doğrudan ülke bilgisi bulunmuyor. türkiyeyi içine alan koordinat bilgilerini kullanacağız. dikdörtgen şeklinde bir veri çekeceğimiz için sınırımızda diğer ülke verileride içinde yer alıyor.

kodu çalıştırdığımızda

ookla_turkey_2025_Q4.parquet

isminde bir dosyamız olacak.. bu dosya içerisindeki verileri incelemek için biraz görsellik katalım… dash kullanarak aşagıdaki kodu oluşturdum

kodu çalıştırdığımızda http://127.0.0.1:8050/ adresinde aşagıdaki sınucu göreceğiz..

github üzerinden proje kodlarına erişebilirsiniz :

https://github.com/ferhatcicek/ookla-turkiye-speedtest-opendata

securecrt commands manager e komut listesi eklemek

ağ yönetiminde ssh client uygulaması olarak securecrt oldukça popülerdir. eğer sizde securecrt kullanıyor ve kullanmayı planlıyorsanız network yönetimi sırasında commands manager aracı oldukça işinize yarayacaktır.

commands manager altıda istediğiniz komut tanımlamalarını yapabiliyor ve tek tıkla bu komutu aktif oturuma gönderebilirsiniz.. tasarım sırasında ağaç yapısı desteklemesi sayesinde kategorize edilmiş olarak komutları ekleyebilirsiniz…

tüm ihtiyacınız olabilecek komutları tek tek eklemez biraz yorucu olabilir.. bu noktada hazırladığım python scripti paylaşmacağım.. öncelikle ekleyeceğimiz komutları aşagıdaki formatta excel dosyasında hazırlıyoruz. vendor ve category olarak bir ağaç yapısı tasarladık.

commands.xlsx

Vendor Category Command
nokia bgp show router bgp summary
nokia bgp show router bgp neighbor
nokia switch show ethernet-service port 1/3
huawei display ip interface brief
zte show ip interface brief loopback0

xml_create.py

import pandas as pd
import xml.etree.ElementTree as ET
from xml.dom import minidom

def create_securecrt_xml(excel_file_path, output_xml_path):
    # Excel dosyasını oku ve NaN değerleri boş string ile değiştir
    df = pd.read_excel(excel_file_path).fillna("")
    
    # Ana XML yapısını oluştur
    root = ET.Element("VanDyke", version="3.0")
    commands_root = ET.SubElement(root, "key", name="Commands")
    
    # Vendor gruplarına göre işle
    for vendor in df["Vendor"].unique():
        if not vendor:  # Vendor boşsa atla
            continue
            
        vendor_key = ET.SubElement(commands_root, "key", name=str(vendor))
        
        # Kategoriye göre komutları grupla
        vendor_data = df[df["Vendor"] == vendor]
        for category in vendor_data["Category"].unique():
            if pd.isna(category) or category == "":  # Kategori boşsa genel komutlara ekle
                continue
                
            category_data = vendor_data[vendor_data["Category"] == category]
            category_key = ET.SubElement(vendor_key, "key", name=str(category))
            commands_key = ET.SubElement(category_key, "key", name="__Commands__")
            default_array = ET.SubElement(commands_key, "array", name="Default")
            
            # Komutları ekle
            for _, row in category_data.iterrows():
                if not row["Command"] or pd.isna(row["Command"]):
                    continue
                command_str = f"SEND,{row['Command']},{row['Command']},,,0,1,{row['Command']},"
                ET.SubElement(default_array, "string").text = command_str
        
        # Vendor için genel komutlar (kategori yoksa)
        general_commands = vendor_data[vendor_data["Category"].isna() | (vendor_data["Category"] == "")]
        if not general_commands.empty:
            commands_key = ET.SubElement(vendor_key, "key", name="__Commands__")
            default_array = ET.SubElement(commands_key, "array", name="Default")
            for _, row in general_commands.iterrows():
                if not row["Command"] or pd.isna(row["Command"]):
                    continue
                command_str = f"SEND,{row['Command']},{row['Command']},,,0,1,{row['Command']},"
                ET.SubElement(default_array, "string").text = command_str
    
    # XML'i düzgün formatla ve kaydet
    xml_str = ET.tostring(root, encoding="utf-8")
    dom = minidom.parseString(xml_str)
    # toprettyxml encoding="utf-8" belirtilirse bytes döndürür, biz manuel yazıyoruz
    body = dom.toprettyxml(indent="\t")
    # toprettyxml'in ürettiği ilk satırı (<?xml ...?>) çıkar, yerine istediğimizin koy
    lines = body.splitlines()
    lines[0] = '<?xml version="1.0" encoding="UTF-8"?>'
    # Boş satırları temizle (toprettyxml bazen ekstra boş satır ekler)
    clean_lines = [l for l in lines if l.strip() != ""]
    pretty_xml = "\n".join(clean_lines) + "\n"
    
    with open(output_xml_path, "w", encoding="utf-8") as f:
        f.write(pretty_xml)

if __name__ == "__main__":
    excel_file_path = "commands.xlsx"  # Excel dosyası yolu
    output_xml_path = "securecrt_commands.xml"  # Çıktı XML dosyası yolu
    create_securecrt_xml(excel_file_path, output_xml_path)
    print(f"XML dosyası oluşturuldu: {output_xml_path}")

excel ve python dosyasını ayını dizinde olacak şekilde çalıştırırsak aynı dizinde securecrt_commands.xml adından bir xml dosyası oluşturulacaktır.

<?xml version="1.0" encoding="UTF-8"?>
<VanDyke version="3.0">
	<key name="Commands">
		<key name="nokia">
			<key name="bgp">
				<key name="__Commands__">
					<array name="Default">
						<string>SEND,show router bgp summary,show router bgp summary,,,0,1,show router bgp summary,</string>
						<string>SEND,show router bgp neighbor,show router bgp neighbor,,,0,1,show router bgp neighbor,</string>
					</array>
				</key>
			</key>
			<key name="switch">
				<key name="__Commands__">
					<array name="Default">
						<string>SEND,show ethernet-service port 1/3,show ethernet-service port 1/3,,,0,1,show ethernet-service port 1/3,</string>
					</array>
				</key>
			</key>
		</key>
		<key name="huawei">
			<key name="__Commands__">
				<array name="Default">
					<string>SEND,display ip interface brief,display ip interface brief,,,0,1,display ip interface brief,</string>
				</array>
			</key>
		</key>
		<key name="zte">
			<key name="__Commands__">
				<array name="Default">
					<string>SEND,show ip interface brief loopback0,show ip interface brief loopback0,,,0,1,show ip interface brief loopback0,</string>
				</array>
			</key>
		</key>
	</key>
</VanDyke>

xml dosyası oluşturktan sonra aşagıdaki adımları izlerek xml dosyasını securecrt içine import edeceğiz.

github deposu için

https://github.com/ferhatcicek/securecrt-commands-manager-xml-create

excel de gereksiz sütun temizliği

excel olarak aldığımız bir rapor olduğunu varsayalım. bir sütundaki değerler tüm satırlarda aynı veriye sahipse bu sütun veri incelemede genelde gereksiz olabilir… bu şekilde çok fazla sütun varsa bunlardan kurtulmalmak için aşagdaıki bir kaç satırlık python kodunu kullanabiliriz.

NSP den aldığım örnek bir raporda 203 sutun mevcuttu. Bu kod sonrası 33 sutuna düşmüş oldu.

import pandas as pd

# Excel dosyasını oku
df = pd.read_excel("liste.xlsx")

# Tüm satırlarda aynı olan sütunları bul ve sil
df = df.loc[:, df.nunique() > 1]

# Sonucu kaydet
df.to_excel("liste_temiz.xlsx", index=False)

python ile youtube dan oynatma listesini mp3 olarak indirmek

python ile youtube dan mp3 indirmek konu yazı sonrası tek tek indirmek yerine playlisti tek bir sefer nasıl indirebiliriz sorusu geldi..

bunu takibi yapabiliriz.. ufak bir değişiklik ile oynatma listesini indirebiliriz.. kodumuz aşagıdaki şekilde olacaktır.

import yt_dlp

def oynatma_listesi_indir(oynatma_listesi_adresi, output_folder="mp3_klasor"):
    options = {
        'format': 'bestaudio/best',
        'outtmpl': f'{output_folder}/%(title)s.%(ext)s',  
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '192',
        }],
        'noplaylist': True  
    }

    with yt_dlp.YoutubeDL(options) as ydl:
        ydl.download([oynatma_listesi_adresi])

# Kullanım
oynatma_listesi_adresi = "https://www.youtube.com/playlist?list=<oynatma_listesi_id"
oynatma_listesi_indir(oynatma_listesi_adresi, output_folder="mp3_klasor")

burada dikkat edilmesi gereken nokta listedeki tüm videoların aktif olmasıdır. kodda hata denetimi yapmadığımız için herhangi bir video silindiyse kod o noktada kesilecektir.

python ile youtube dan mp3 indirmek

bir çoğumuzun hayatından artık mp3 dosyaları çıktı. artık sevidğimiz müzikleri ya online dinliyoruz yada tercih ettiğimiz bir uygulamanın offline modunu kullanıyoruz.

benim gibi bir kaç mp3 indirmek isteyen çıkabilir.

bunun için reklamlarla dolu video dosya içerisinden ses dosyasını kaydetmenize sağlayan bir sürü site var.. isterseniz bunlardan birini kullanabillirsiniz.. ama ben bunlarla uğraşmak istemediğim için basit bir uygulama yapmak istedim..

kodu tabiki pythonda yazacağız.. kod sırasında bize yardımcı olacak bir çok modül mevcut. bunların bir çoğu ffmpeg kullanıyor ve pc nizde kurulu olmasını şart koşuyor.

bu noktada yt_dlp yardımımıza yetişiyor. denediğim modüller arasında en sağlık çalışanı yt_dlp oldu.

şimdi adresini bildiğimiz bir youttube url için yt_dlp modulunu kullanarak mp3 dosyasını nasıl elde ederiz basit bir örnek yapalım.

import yt_dlp

def muzik_dosyasi_indir(video_url, output_folder="mp3_klasor"):
    options = {
        'format': 'bestaudio/best',
        'outtmpl': f'{output_folder}/%(title)s.%(ext)s',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '192',
        }],
        'noplaylist': True
    }

    with yt_dlp.YoutubeDL(options) as ydl:
        ydl.download([video_url])

video_url = "https://www.youtube.com/watch?v=<video_id>"
muzik_dosyasi_indir(video_url, output_folder="mp3_klasor")

temel kodumuz yukarıdaki gibi olacaktır… mp3 olarak indirmek istediğiniz bir video dosyasının idsini koddaki <video_id> ile değiştirir ve kodu çalıştırsanız aşagıdaki gibi çıktı ile çarşılacaksınız.

[youtube] Extracting URL: https://www.youtube.com/watch?v=8umGN3KiGY4
[youtube] 8umGN3KiGY4: Downloading webpage
[youtube] 8umGN3KiGY4: Downloading tv client config
[youtube] 8umGN3KiGY4: Downloading player e7567ecf
[youtube] 8umGN3KiGY4: Downloading tv player API JSON
[youtube] 8umGN3KiGY4: Downloading ios player API JSON
[youtube] 8umGN3KiGY4: Downloading m3u8 information
[info] 8umGN3KiGY4: Downloading 1 format(s): 251
[download] Destination: mp3_klasor\Passenger - Let Her Go.webm
[download] 100% of    4.05MiB in 00:00:00 at 8.79MiB/s
[ExtractAudio] Destination: mp3_klasor\Passenger - Let Her Go.mp3
Deleting original file mp3_klasor\Passenger - Let Her Go.webm (pass -k to keep)

günsan elektrik – tuya destekli akıllı priz

uzaktan kontrol ve zamanlama için bir adet akıllı priz ihtiyacı oldu. bir alış veriş sitesinden kampanyadan faydalanarak günsan elektrik e ait olan prizden sipariş verdim. ürünün resmi sayfası

https://www.gunsanelectric.com/urunler/anahtar-priz/smart/wi-fi-kontrollu-akilli-priz-16a

şeklinde..

yerli ürün alalım diye düşürken içten içe üzerine günsan yazılmış fason olarak üretilmiş bir ürün alaağımı biliyordum. günsan smart life uygulamasını kendisine göre uyarlamış ama eksiklerde kalmış.. bazı yerlerde hala smartlife yazıyor 🙂

günsanın gg smart isimli uygulamasını kullanarak kısa sürede ürünü uygulamaya sorunsuz olarak ekleyebiliyorsunuz. tuya veya smart life uygulamasını kullanmak istersenizde sorun yaşamıyorsunuz.

buraya kadar sorun yok ancak sizde benim gibi uygulamalarda istediğinizi yapamıyorsanız, verilerinizi dış dünya ile paylaşmak istemiyor ve olası güvenlik açıklarının önüne geçmek istiyebilirsiniz.

bunun için kendi uygulamamızı yazabiliriz veya evinizde çalıştırdığınız bir akıllı ev asistanına ekleyebilirsiniz. ancak bunu yapabilmeniz için cihazın iletşim prokolu vb bilgileri gerekli. bu bilgiler ne yazıkkı cihaz ile doğrudan size gelmiyor.

adım adım bu bilgileri nasıl elde edeceğimize ve nasıl basit bir program yazacağımıza bakalım.

öncelikle akıllı prizinize smart life uygulamasına doğru şekilde ekleyin.

akıllı priz wifi desteğine sahip olduğu için ipsini öğrenmeliyiz. bunu ağınızda ip taraması veya modem arayüzünden rahatlıkla bulabilirsiniz. sonrasına bir port scanner ile açık olan portları bulmalıyız… bu ürün 6666, 6667, 6668 portlarını kullanıyor.

ihtiyacımız olan diğer bilgilere ulaşmanın bir kaç yöntemi var.

en temel haliyle yakadığımız pakeleri analiz ederek bu verilere ulaşabiliriz.. mitm, proy , wireshak vb ile uğraşmayı seviyersanız konuya zaten hekimsinizdir burada anlatmayacağım, siz hallederseniz. biz daha basit olan yöntemlere bakalım.

tuya geliştirici ortamı üzerinden nasıl öğreneceğimizi inceleyelim. öncelikle

https://developer.tuya.com/en

adresinden kendimize bir hesap oluşturalım. hesap oluşumunda sonra

https://platform.tuya.com/cloud

adresinden bir proje oluşturalım.. proje oluştururken aşagıdaki parametreleri kullanabilirsiniz. dikkat etmeniz gereken nokta data center seçimi olacak. ileleyen aşamalarda yapacağımız bazı işlemlerde seçtiğiniz data center önem kazanıyor.. US veya Central Europe seçmenizi öneririm..

sonrasında kullanacağınız api servislerini belirlemeniz gerekiyor. Smart Home Content Manage, [Deprecate]Device Log Query , Smart Home Basic Service, [Deprecate]Smart Home Scene Linkage servislerinin seçili olması olmasına dikkat edelim.

projeyi oluşturduktan sonra aşagıdaki gibi ekran bizi karşılayacaktır.

Device altına giriyoruz

sonrasında Link App Account a seçip Add App Account butonuna tıklıyoruz. açılan penceredki qr kodu

smart life uygulamasında tanımlama kısmında taratacağız. bu işlem başarılı olarak tamamlandıktan sonra smart life uygulamasına eklediğiniz tuya destekli cihazları platformda görmeye başlayacaksınız

Device Permission ayarlarını Controllable olarak ayarlayın.. buraya kadar yaptıklarımız sayesinde tuya developer üzerinden akıllı prizlerimizi kontrol edebilir ve izleyebilir duruma getirmiş olduk.

şimdi api explorer i açalım.

https://platform.tuya.com/cloud/explorer

platformu açtıktan sonra “query device details” sorgusu altında device list altında gördüğümüz device id bilgisini girerek

sorguyu çalıştırdığımızda aşagıdaki gibi bir sonuç elde ediyoruz. product id ve model bilgisinden ürünün bir fason olduğunu görüyoruz.

{
  "result": {
    "active_time": 1738437687,
    "bind_space_id": "223209011",
    "category": "cz",
    "create_time": 1738180007,
    "custom_name": "tv",
    "icon": "smart/icon/ay1544008322541hl9iQ/9aebc86a6392f0b9495d826cba17ba54.jpg",
    "id": "xxxxxxxxxxxxxxxxxxxx",
    "ip": "11.11.11.11",
    "is_online": true,
    "lat": "38.74",
    "local_key": "xxxxxxxxxxxxxxxxxxxx",
    "lon": "35.44",
    "model": "EU02A-中性欧规EU02A-16A计量CB2S-BK7231N 过充保护",
    "name": "Smart plug 2",
    "product_id": "newhgkiotowsaryi",
    "product_name": "Smart Plug",
    "sub": false,
    "time_zone": "+03:00",
    "update_time": 1738437697,
    "uuid": "xxxxxxxxxxxxxxxxxxxx"
  },
  "success": true,
  "t": 1738528737555,
  "tid": "xxxxxxxxxxxxxxxxxxxx"
}

elde ettiğimiz bu bilgilerle lokalden akıllı prize bağlanıp veri çekebiliriz.

Alacağımız veriler bize doğrudan bir şey ifade etmeyebilir. anlamlı hale getirmek için Query Things Data Model altından data modelini elde edelim.

elde edilen çıktı aşagıdaki şekildedir…

{
  "result": {
    "model": "{\"modelId\":\"000004yex6\",\"services\":[{\"actions\":[],\"code\":\"\",\"description\":\"\",\"events\":[],\"name\":\"默认服务\",\"properties\":[{\"abilityId\":1,\"accessMode\":\"rw\",\"code\":\"switch_1\",\"description\":\"\",\"extensions\":{\"iconName\":\"icon-dp_power2\",\"attribute\":\"641\"},\"name\":\"开关1\",\"typeSpec\":{\"type\":\"bool\"}},{\"abilityId\":9,\"accessMode\":\"rw\",\"code\":\"countdown_1\",\"description\":\"\",\"extensions\":{\"iconName\":\"icon-dp_time2\",\"attribute\":\"736\"},\"name\":\"开关1倒计时\",\"typeSpec\":{\"type\":\"value\",\"max\":86400,\"min\":0,\"scale\":0,\"step\":1,\"unit\":\"s\"}},{\"abilityId\":17,\"accessMode\":\"ro\",\"code\":\"add_ele\",\"description\":\"\",\"extensions\":{\"attribute\":\"704\"},\"name\":\"增加电量\",\"typeSpec\":{\"type\":\"value\",\"max\":50000,\"min\":0,\"scale\":3,\"step\":100}},{\"abilityId\":18,\"accessMode\":\"ro\",\"code\":\"cur_current\",\"description\":\"\",\"extensions\":{\"attribute\":\"704\"},\"name\":\"当前电流\",\"typeSpec\":{\"type\":\"value\",\"max\":30000,\"min\":0,\"scale\":0,\"step\":1,\"unit\":\"mA\"}},{\"abilityId\":19,\"accessMode\":\"ro\",\"code\":\"cur_power\",\"description\":\"\",\"extensions\":{\"attribute\":\"704\"},\"name\":\"当前功率\",\"typeSpec\":{\"type\":\"value\",\"max\":80000,\"min\":0,\"scale\":1,\"step\":1,\"unit\":\"W\"}},{\"abilityId\":20,\"accessMode\":\"ro\",\"code\":\"cur_voltage\",\"description\":\"\",\"extensions\":{\"attribute\":\"704\"},\"name\":\"当前电压\",\"typeSpec\":{\"type\":\"value\",\"max\":5000,\"min\":0,\"scale\":1,\"step\":1,\"unit\":\"V\"}},{\"abilityId\":21,\"accessMode\":\"ro\",\"code\":\"test_bit\",\"description\":\"\",\"extensions\":{\"attribute\":\"736\"},\"name\":\"产测结果位\",\"typeSpec\":{\"type\":\"value\",\"max\":5,\"min\":0,\"scale\":0,\"step\":1}},{\"abilityId\":22,\"accessMode\":\"ro\",\"code\":\"voltage_coe\",\"description\":\"\",\"extensions\":{\"attribute\":\"736\"},\"name\":\"电压校准系数\",\"typeSpec\":{\"type\":\"value\",\"max\":1000000,\"min\":0,\"scale\":0,\"step\":1}},{\"abilityId\":23,\"accessMode\":\"ro\",\"code\":\"electric_coe\",\"description\":\"\",\"extensions\":{\"attribute\":\"736\"},\"name\":\"电流校准系数\",\"typeSpec\":{\"type\":\"value\",\"max\":1000000,\"min\":0,\"scale\":0,\"step\":1}},{\"abilityId\":24,\"accessMode\":\"ro\",\"code\":\"power_coe\",\"description\":\"\",\"extensions\":{\"attribute\":\"736\"},\"name\":\"功率校准系数\",\"typeSpec\":{\"type\":\"value\",\"max\":1000000,\"min\":0,\"scale\":0,\"step\":1}},{\"abilityId\":25,\"accessMode\":\"ro\",\"code\":\"electricity_coe\",\"description\":\"\",\"extensions\":{\"attribute\":\"736\"},\"name\":\"电量校准系数\",\"typeSpec\":{\"type\":\"value\",\"max\":1000000,\"min\":0,\"scale\":0,\"step\":1}},{\"abilityId\":26,\"accessMode\":\"ro\",\"code\":\"fault\",\"description\":\"\",\"extensions\":{\"attribute\":\"640\"},\"name\":\"故障告警\",\"typeSpec\":{\"type\":\"bitmap\",\"label\":[\"ov_cr\",\"ov_vol\",\"ov_pwr\",\"ls_cr\",\"ls_vol\",\"ls_pow\"],\"maxlen\":6}},{\"abilityId\":38,\"accessMode\":\"rw\",\"code\":\"relay_status\",\"description\":\"\",\"extensions\":{\"iconName\":\"icon-zhuangtai\",\"attribute\":\"736\"},\"name\":\"上电状态设置\",\"typeSpec\":{\"type\":\"enum\",\"range\":[\"off\",\"on\",\"memory\"]}},{\"abilityId\":39,\"accessMode\":\"rw\",\"code\":\"overcharge_switch\",\"description\":\"\",\"extensions\":{\"attribute\":\"128\"},\"name\":\"过充保护\",\"typeSpec\":{\"type\":\"bool\"}},{\"abilityId\":40,\"accessMode\":\"rw\",\"code\":\"light_mode\",\"description\":\"\",\"extensions\":{\"iconName\":\"tcl_function_light\",\"attribute\":\"224\"},\"name\":\"指示灯状态设置\",\"typeSpec\":{\"type\":\"enum\",\"range\":[\"relay\",\"pos\",\"none\",\"on\"]}},{\"abilityId\":41,\"accessMode\":\"rw\",\"code\":\"child_lock\",\"description\":\"\",\"extensions\":{\"iconName\":\"icon-dp_power2\",\"attribute\":\"128\"},\"name\":\"童锁开关\",\"typeSpec\":{\"type\":\"bool\"}},{\"abilityId\":42,\"accessMode\":\"rw\",\"code\":\"cycle_time\",\"description\":\"涂鸦协议\",\"extensions\":{\"iconName\":\"icon-dp_time3\",\"attribute\":\"224\"},\"name\":\"循环定时\",\"typeSpec\":{\"type\":\"string\",\"maxlen\":255}},{\"abilityId\":43,\"accessMode\":\"rw\",\"code\":\"random_time\",\"description\":\"涂鸦协议\",\"extensions\":{\"iconName\":\"icon-dp_time2\",\"attribute\":\"224\"},\"name\":\"随机定时\",\"typeSpec\":{\"type\":\"string\",\"maxlen\":255}},{\"abilityId\":44,\"accessMode\":\"rw\",\"code\":\"switch_inching\",\"description\":\"涂鸦协议\",\"extensions\":{\"attribute\":\"224\"},\"name\":\"点动开关\",\"typeSpec\":{\"type\":\"string\",\"maxlen\":255}}]}]}"
  },
  "success": true,
  "t": 1738532745188,
  "tid": "0e8bf1f9e1af11ef9e609e9247cde4aa"
}

görüleceği üzere açıklamalar vb çince.. bunu python altında kullanmak için anlamlı hale getirelim.

# DPS tanımları
DPS_MAPPING = {
    '1': {
        'id': 1,
        'name': 'Güç Anahtarı',
        'code': 'switch_1',
        'type': bool,
        'access': 'rw',
        'icon': 'icon-dp_power2',
        'format': lambda x: 'Açık' if x else 'Kapalı'
    },
    '9': {
        'id': 9,
        'name': 'Geri Sayım',
        'code': 'countdown_1',
        'type': int,
        'access': 'rw',
        'icon': 'icon-dp_time2',
        'max': 86400,
        'min': 0,
        'scale': 0,
        'step': 1,
        'unit': 'saniye',
        'format': lambda x: f'{x} saniye'
    },
    '17': {
        'id': 17,
        'name': 'Toplam Enerji',
        'code': 'add_ele',
        'type': int,
        'access': 'ro',
        'max': 50000,
        'min': 0,
        'scale': 3,
        'step': 100,
        'format': lambda x: f'{x/1000:.3f} kWh'
    },
    '18': {
        'id': 18,
        'name': 'Anlık Akım',
        'code': 'cur_current',
        'type': int,
        'access': 'ro',
        'max': 30000,
        'min': 0,
        'unit': 'mA',
        'format': lambda x: f'{x/1000:.2f} A'
    },
    '19': {
        'id': 19,
        'name': 'Anlık Güç',
        'code': 'cur_power',
        'type': int,
        'access': 'ro',
        'max': 80000,
        'min': 0,
        'scale': 1,
        'unit': 'W',
        'format': lambda x: f'{x/10:.1f} W'
    },
    '20': {
        'id': 20,
        'name': 'Anlık Voltaj',
        'code': 'cur_voltage',
        'type': int,
        'access': 'ro',
        'max': 5000,
        'min': 0,
        'scale': 1,
        'unit': 'V',
        'format': lambda x: f'{x/10:.1f} V'
    },
    '21': {
        'id': 21,
        'name': 'Test Sonucu',
        'code': 'test_bit',
        'type': int,
        'access': 'ro',
        'max': 5,
        'min': 0,
        'format': lambda x: f'Test Sonucu: {x}'
    },
    '26': {
        'id': 26,
        'name': 'Hata Durumu',
        'code': 'fault',
        'type': int,
        'access': 'ro',
        'labels': ['Aşırı Akım', 'Aşırı Voltaj', 'Aşırı Güç', 'Düşük Akım', 'Düşük Voltaj', 'Düşük Güç'],
        'format': lambda x: decode_fault(x)
    },
    '38': {
        'id': 38,
        'name': 'Röle Durumu',
        'code': 'relay_status',
        'type': str,
        'access': 'rw',
        'icon': 'icon-zhuangtai',
        'range': ['off', 'on', 'memory'],
        'format': lambda x: {'off': 'Kapalı', 'on': 'Açık', 'memory': 'Hafıza'}.get(x, x)
    },
    '39': {
        'id': 39,
        'name': 'Aşırı Şarj Koruması',
        'code': 'overcharge_switch',
        'type': bool,
        'access': 'rw',
        'format': lambda x: 'Aktif' if x else 'Pasif'
    },
    '40': {
        'id': 40,
        'name': 'LED Gösterge Modu',
        'code': 'light_mode',
        'type': str,
        'access': 'rw',
        'icon': 'tcl_function_light',
        'range': ['relay', 'pos', 'none', 'on'],
        'format': lambda x: {'relay': 'Röle', 'pos': 'Pozisyon', 'none': 'Kapalı', 'on': 'Açık'}.get(x, x)
    },
    '41': {
        'id': 41,
        'name': 'Çocuk Kilidi',
        'code': 'child_lock',
        'type': bool,
        'access': 'rw',
        'icon': 'icon-dp_power2',
        'format': lambda x: 'Kilitli' if x else 'Kilitsiz'
    },
    '42': {
        'id': 42,
        'name': 'Döngü Zamanlayıcı',
        'code': 'cycle_time',
        'type': str,
        'access': 'rw',
        'icon': 'icon-dp_time3',
        'maxlen': 255,
        'format': lambda x: f'Döngü: {x}'
    },
    '43': {
        'id': 43,
        'name': 'Rastgele Zamanlayıcı',
        'code': 'random_time',
        'type': str,
        'access': 'rw',
        'icon': 'icon-dp_time2',
        'maxlen': 255,
        'format': lambda x: f'Rastgele: {x}'
    },
    '44': {
        'id': 44,
        'name': 'Anlık Anahtar',
        'code': 'switch_inching',
        'type': str,
        'access': 'rw',
        'maxlen': 255,
        'format': lambda x: f'Anlık: {x}'
    }
}

def decode_fault(fault_code):
    faults = []
    fault_map = {
        0: "Aşırı Akım",
        1: "Aşırı Voltaj", 
        2: "Aşırı Güç",
        3: "Düşük Akım",
        4: "Düşük Voltaj",
        5: "Düşük Güç"
    }
    
    for bit, fault in fault_map.items():
        if fault_code & (1 << bit):
            faults.append(fault)
    
    return ', '.join(faults) if faults else 'Normal'

şimdi tinyyuya modulunu kullanarak akıllı prizimiden veri çekecek python kodumuzu yazalım…

import tinytuya
import time

# Cihaz bilgileri
DEVICE_ID = "xx"
IP_ADDRESS = "192.168.1.143"
LOCAL_KEY = "xx"
VERSION = 3.4

# DPS tanımları
DPS_MAPPING = {
    '1': {
        'id': 1,
        'name': 'Güç Anahtarı',
        'code': 'switch_1',
        'type': bool,
        'access': 'rw',
        'icon': 'icon-dp_power2',
        'format': lambda x: 'Açık' if x else 'Kapalı'
    },
    '9': {
        'id': 9,
        'name': 'Geri Sayım',
        'code': 'countdown_1',
        'type': int,
        'access': 'rw',
        'icon': 'icon-dp_time2',
        'max': 86400,
        'min': 0,
        'scale': 0,
        'step': 1,
        'unit': 'saniye',
        'format': lambda x: f'{x} saniye'
    },
    '17': {
        'id': 17,
        'name': 'Toplam Enerji',
        'code': 'add_ele',
        'type': int,
        'access': 'ro',
        'max': 50000,
        'min': 0,
        'scale': 3,
        'step': 100,
        'format': lambda x: f'{x/1000:.3f} kWh'
    },
    '18': {
        'id': 18,
        'name': 'Anlık Akım',
        'code': 'cur_current',
        'type': int,
        'access': 'ro',
        'max': 30000,
        'min': 0,
        'unit': 'mA',
        'format': lambda x: f'{x/1000:.2f} A'
    },
    '19': {
        'id': 19,
        'name': 'Anlık Güç',
        'code': 'cur_power',
        'type': int,
        'access': 'ro',
        'max': 80000,
        'min': 0,
        'scale': 1,
        'unit': 'W',
        'format': lambda x: f'{x/10:.1f} W'
    },
    '20': {
        'id': 20,
        'name': 'Anlık Voltaj',
        'code': 'cur_voltage',
        'type': int,
        'access': 'ro',
        'max': 5000,
        'min': 0,
        'scale': 1,
        'unit': 'V',
        'format': lambda x: f'{x/10:.1f} V'
    },
    '21': {
        'id': 21,
        'name': 'Test Sonucu',
        'code': 'test_bit',
        'type': int,
        'access': 'ro',
        'max': 5,
        'min': 0,
        'format': lambda x: f'Test Sonucu: {x}'
    },
    '26': {
        'id': 26,
        'name': 'Hata Durumu',
        'code': 'fault',
        'type': int,
        'access': 'ro',
        'labels': ['Aşırı Akım', 'Aşırı Voltaj', 'Aşırı Güç', 'Düşük Akım', 'Düşük Voltaj', 'Düşük Güç'],
        'format': lambda x: decode_fault(x)
    },
    '38': {
        'id': 38,
        'name': 'Röle Durumu',
        'code': 'relay_status',
        'type': str,
        'access': 'rw',
        'icon': 'icon-zhuangtai',
        'range': ['off', 'on', 'memory'],
        'format': lambda x: {'off': 'Kapalı', 'on': 'Açık', 'memory': 'Hafıza'}.get(x, x)
    },
    '39': {
        'id': 39,
        'name': 'Aşırı Şarj Koruması',
        'code': 'overcharge_switch',
        'type': bool,
        'access': 'rw',
        'format': lambda x: 'Aktif' if x else 'Pasif'
    },
    '40': {
        'id': 40,
        'name': 'LED Gösterge Modu',
        'code': 'light_mode',
        'type': str,
        'access': 'rw',
        'icon': 'tcl_function_light',
        'range': ['relay', 'pos', 'none', 'on'],
        'format': lambda x: {'relay': 'Röle', 'pos': 'Pozisyon', 'none': 'Kapalı', 'on': 'Açık'}.get(x, x)
    },
    '41': {
        'id': 41,
        'name': 'Çocuk Kilidi',
        'code': 'child_lock',
        'type': bool,
        'access': 'rw',
        'icon': 'icon-dp_power2',
        'format': lambda x: 'Kilitli' if x else 'Kilitsiz'
    },
    '42': {
        'id': 42,
        'name': 'Döngü Zamanlayıcı',
        'code': 'cycle_time',
        'type': str,
        'access': 'rw',
        'icon': 'icon-dp_time3',
        'maxlen': 255,
        'format': lambda x: f'Döngü: {x}'
    },
    '43': {
        'id': 43,
        'name': 'Rastgele Zamanlayıcı',
        'code': 'random_time',
        'type': str,
        'access': 'rw',
        'icon': 'icon-dp_time2',
        'maxlen': 255,
        'format': lambda x: f'Rastgele: {x}'
    },
    '44': {
        'id': 44,
        'name': 'Anlık Anahtar',
        'code': 'switch_inching',
        'type': str,
        'access': 'rw',
        'maxlen': 255,
        'format': lambda x: f'Anlık: {x}'
    }
}

def decode_fault(fault_code):
    faults = []
    fault_map = {
        0: "Aşırı Akım",
        1: "Aşırı Voltaj", 
        2: "Aşırı Güç",
        3: "Düşük Akım",
        4: "Düşük Voltaj",
        5: "Düşük Güç"
    }
    
    for bit, fault in fault_map.items():
        if fault_code & (1 << bit):
            faults.append(fault)
    
    return ', '.join(faults) if faults else 'Normal'

def check_device_status(device):
    try:
        status = device.status()
        
        if status and 'dps' in status:
            dps = status['dps']
            print("\n=== Cihaz Durumu ===")
            
            for key, value in dps.items():
                if key in DPS_MAPPING:
                    mapping = DPS_MAPPING[key]
                    try:
                        if isinstance(value, mapping['type']):
                            formatted_value = mapping['format'](value)
                            print(f"{mapping['name']}: {formatted_value}")
                        else:
                            print(f"{mapping['name']}: Tip hatası")
                    except Exception as e:
                        print(f"{mapping['name']}: Formatlama hatası - {str(e)}")
            
            print("\n=== Ham Veri ===")
            print(status)
        else:
            print("Cihaz durumu alınamadı!")
            
    except Exception as e:
        print(f"Durum kontrolünde hata: {e}")
        return None

def connect_device():
    try:
        device = tinytuya.OutletDevice(
            dev_id=DEVICE_ID,
            address=IP_ADDRESS,
            local_key=LOCAL_KEY
        )
        device.set_version(VERSION)
        return device
    except Exception as e:
        print(f"Cihaz bağlantısı hatası: {e}")
        return None

def main():
    device = connect_device()
    if not device:
        print("Program sonlandırılıyor...")
        return
    
    print("Cihaza bağlanıldı...")
    check_device_status(device)

if __name__ == "__main__":
    main()

kodu çalıştırınca aşagıdaki çıktı ile karşılacağız…

Cihaza bağlanıldı...

=== Cihaz Durumu ===
Güç Anahtarı: Açık
Geri Sayım: 0 saniye
Toplam Enerji: 0.100 kWh
Anlık Akım: 1.24 A
Anlık Güç: 279.3 W
Anlık Voltaj: 233.1 V
Test Sonucu: Test Sonucu: 1
Hata Durumu: Normal
Röle Durumu: Hafıza
Aşırı Şarj Koruması: Pasif
LED Gösterge Modu: Röle
Çocuk Kilidi: Kilitsiz
Döngü Zamanlayıcı: Döngü:
Rastgele Zamanlayıcı: Rastgele:
Anlık Anahtar: Anlık:

=== Ham Veri ===
{'dps': {'1': True, '9': 0, '17': 100, '18': 1242, '19': 2793, '20': 2331, '21': 1, '22': 567, '23': 27594, '24': 14940, '25': 2780, '26': 0, '38': 'memory', '39': False, '40': 'relay', '41': False, '42': '', '43': '', '44': ''}}

şimdilik bu kadar…. ikinci bir yazı olursa veriyi loglamayı, analizi ve açıp kapama örneklerini anlatacağım…

Back To Top