Aktualizováno 5.3. 2019

      
 

   Základy programování - Spínačky z minulé úlohy, doplněné o komunikační procedury
 
Základy programování počítačové komunikace - globální proměnné, ukládání do konfiguračního souboru a použití TCP komunikace k odesílání povelů do serveru, který naslouchá.

 

Pro učení nových věcí jsem použil starý program, ve kterém jsem tenkrát komunikaci vymazal, protože jsme se v té lekci učili jiné věci.

Ani tato verze není finální. Má několik chyb, o kterých vím a na které ještě taky dojde někdy příště. Verze však obsahuje nové věci, které potřebujeme teď umět:

- zapisovat a číst data do/z konfiguračního souboru
- ukázat si, co to je globální proměnná
- doplnit náš program o procedury, které pošlou povel na server (a ten ho vykoná).

Pokud máme naprogramovaný TCP Socket server např. v Linuxu na Raspberry Pi nebo Asus Tinker Boardu (tedy na malých Single Board Computerech, SBC velikosti kreditky), můžeme těmito spínačkami v daný čas z desktopu zapínat nebo vypínat relé přes počítačovou síť. Pokud máme alespoň druhý noťas s Linuxem a Gambasem (a tzv. TCP ControlServerem, který naslouchá), můžeme si místo spínání relé obarvovat obdélníčky - viz tato lekce.

A pokud nemáme nic, můžeme si alespoň ve Windows pustit demoverzi, která je ke stažení zde, která se dá jednoduše upravit, aby komunikovala a u které si prohlédneme několik nových věcí v kódu.

Poznámky:
1. Stáhnout spustitelný exáč lze zde.
2. Stáhnout zazipovaný projekt Visual Basic lze zde.

Globální proměnné

Globální proměnné si udrží svůj obsah mimo proceduru, ve které jsme je použili. Ve Visual Basicu i mimo třídu (Class). Globální proměnné se deklarují jako Public, viz příklad kódu dole. Často se deklarují v tzv. modulu (Module1.vb), tak to mám zde i já, ale není to podmínkou, můžete je deklarovat i ve Form1 (vyzkoušejte si). Použil jsem dvě globální proměnné: port a server (do jedné se píše číslo portu, kde server naslouchá, do druhé se píše IP adresa, kde máme server puštěný.

Takové informace se dobře zadávají z formuláře, který vidíte na horním obrázku vlevo vedle puštěných spínaček. Zadávat taková data je docela otrava, zejména, když máte jenom jeden naslouchající server. A tak je dobré dělat to jen jednou a dopsat si pár řádek, aby si tyhle informace uložil program spínaček do konfiguráku.

Konfigurační soubor

S konfiguračním souborem musíme dělat několik věcí:
- vytvořit soubor po otevření Form1 spínaček, pokud neexistuje
- přečíst z něho informace dvou globálních proměnných ( port a server )
- otestovat si, zda jsem informace vyčetli (pokud nikoliv, otevřít si konfigurační dialog na jejich zadání)
- z dialog. wokna zadané informace zapsat do konfiguráku

Zdrojový kód ve Form1:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim soubor As New IO.StreamWriter("spinacky.cnf", True)   'Vytvoří soubor, pokud neexistuje, pokud existuje, tak ho NEPŘEPÍŠE !!! Důležitý je parametr True v proceduře
soubor.Close( ) 'po vytvoření můžeme soubor zavřít

Dim cnf_soubor As New IO.StreamReader("spinacky.cnf") 'protože už soubor existuje, vytvoříme tzv streamreader, pomocí kterého ze souboru čteme po řádcích

server = cnf_soubor.ReadLine     'vyčteme dvě řádky, buď tam bude IP adresa serveru a číslo portu nebo tam nebude nic
port = cnf_soubor.ReadLine

cnf_soubor.Close() 'soubor zavřeme, protože ho nepotřebujemem

If server = "" Then
Dialog1.Show()
'kdyby soubor neobsahoval informace o serveru a portu, otevřeme formulář Dialog1 a informace tam zadáme (a taky do našeho souboru zapíšeme pro příště)
End If

Label2.Text = server + " port: " + Str(port) 'Zobrazˇ IP adresu a port v Label2.Text

End Sub

Zdrojový kód v dialog. wokně:

Imports System.Windows.Forms

Public Class Dialog1

Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click, Button1.Click
 
'Me.DialogResult = System.Windows.Forms.DialogResult.OK

server = TextBox1.Text 'priradi se hodnota promenne server z TextBox1
port = Val(TextBox2.Text)

Dim
cnf_soubor As New IO.StreamWriter("spinacky.cnf") 'vytvoří nový soubor, použije streamwriter a na dalších řádcích tam zapíše do dvou řádek naše informace o serveru a portu
cnf_soubor.WriteLine(server)
cnf_soubor.WriteLine(port)
cnf_soubor.Close()
'zavře soubor, už ho nepotřebujeme
Form1.Label2.Text = server +
" port: " + Str(port) 'Zobrazí nám, co jsme nastavili a uložili, tj. IP adresu a port ve Form1.Label2.Text
Me.Close( ) 'zavře dialog, co bychom v něm dále dělali, že, máme nakonfigurováno a uloženo
End
Sub

Komunikační příkazy

Komunikační příkazy jsme si vysvětlili a odladili v minulé lekci zde. Zde si jenom ověříme, zda je umíme do tohoto programu aplikovat. Pokud máme TCP ControlServer s Linuxem nebo Raspberry PI,
odstraníme tyto apostrofy a dovolíme programu komunikovat. Pokud máme jenom toto PC s Windows, tak si o tom budeme jen povídat a zkoušet bez komunikace.

Komunikační příkazy - kódy v procedurách

Private Sub Send_Zapni()
   povel = System.Text.Encoding.ASCII.GetBytes(
"Zap1") 'priradi se hodnota promenne povel
   Dim client As New TcpClient(server, port) 'deklaruje a otevře noveho TCP klienta
   Dim stream As NetworkStream = client.GetStream() 'deklaruje nově stream a napojí klienta
   stream.Write(povel, 0, povel.Length)
'zapíše byty streamu; pocet bytu je precten z povel.Length
   client.Close()
End Sub

Private Sub Send_Vypni()
   povel = System.Text.Encoding.ASCII.GetBytes(
"Vyp1") 'priradi se hodnota promenne povel
   Dim client As New TcpClient(server, port) 'deklaruje a otevře noveho TCP klienta
   Dim stream As NetworkStream = client.GetStream() 'deklaruje nově stream a napojí klienta
   stream.Write(povel, 0, povel.Length)
'zapˇçe byty streamu; pocet bytu je precten z povel.Length
   client.Close()
End Sub

Poznámka:
1. Kódy jsou vidlácké a obsahují celou řadu chyb a velice "neprofesionálních" obratů. Ale fungují a jsou minimalizované právě natolik, abychom pochopili principy globálních proměnných, zápisů do souborů, zápisů do Socketů, principy streamreaderu a streamwriteru.

Detaily, které se mi do textu nevešly

1. Náhled na obsah konfiguračního souboru:

2. Náhled do adresáře, kde se konfigurák vytvoří. Úmyslně jsem použil vidláckou kompilaci do jediného exe souboru, který je spustitelný (jde o time_control.exe). Nic se neinstaluje. Až nás exáč nebude bavit, tak ho smažeme a nebudeme mít počítač zasraný nějakým poinstalačním sajrajtwarem. Konfiguráku jsem nezadal nikam žádnou cestu. Je to vidlácké, ale vím, že ho najdu v adresáři hned vedle toho exáče (spinacky.cnf), až mě nebude bavit, smažu ho. Tyhle jednoduché vidlácké věci jde zatím stále dělat ve Windows a pokud se někdy bavím o konkrétní počítačové svobodě, tak toto za svobodu spouštět si své exáče já opravdu považuji. Proč instalovat, když to není třeba, proč se jebat s repozitáři, když to není třeba ....

3. Spuštění více instancí programu

Spuštění více instancí je pro koncepci našich spínaček důležitá věc. Což o to, spustíme (jako dole). Obdélníčky si obarvíme, ale to je asi tak všechno. program, tak, jak je napsaný, má podstatnou koncepční chybu. Měl jich více. Ale já chci teď zadat domácí úkoly - viz pod obrázkem:

4. Jednu chybu jsem odstranil. Program odesílal na server požadavek na spínání při každém testování spínacích časů. To už není vidlácké, to je opravdový a neskutečný humus. Proto jsem v programu udělal pomocnou proměnnou stav. Tu si při testech měním podle jejich výsledků a nakonec si otestuji, zda je třeba poslat povel k zapnutí nebo vypnutí.

5. Další chybu, která vznikla nedotaženou koncepcí, jsem nechal. A sice, když si pustím tlačítkem "Start dalších hodin" další instance, budou se mi tyto prát mezi sebou. Jedny budou chtít, aby bylo zapnuto, jiné, aby bylo vypnuto. Tento úkol je na přemýšlení: Vymyslete, jak to udělat, aby spínačky byly zapnuté, pokud alespoň jedny hodiny posílají povel Zapnuto (svítí jim zelený pruh, na obrázku jsou to ty vlevo). Řešit můžete na TCP Clientovi nebo na TCP ControlServeru nebo v obou aplikacích.
A připomněli jste mi, že jsem zapomněl ještě na jednu věc, jak se dělá. Když potřebujete z jedné aplikace pustit druhou, jde to příkazem Shell a dělal jsem to např. takto:
 

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
    Shell(
"time_control.exe", AppWinStyle.NormalFocus) ' po kliknutí spouští naše aplikace sama sebe v další instanci
End Sub

Zdravím, právě se vláček blíží k domovu, víc toho dneska nenapíšu ...

 

Zpět na obsah


TU 73, Mira, ok1ufc