-1

I try to write a little batch script. It should play a sound if my phone joins my network.

@echo off
:A
ping -n 1 xxx.xxx.xxx.xx | findstr TTL && start airsiren.wav
goto A

The problem is now that if the phone is detected, it repeatedly starts the sound. But it's supposed to just play once.

Does anyone know a simple fix? Maybe with an IF condition?

I haven't been doing much with batch, but I think I got some basic knowledge.

Mofi
  • 46,139
  • 17
  • 80
  • 143
J4ck
  • 13
  • 4

4 Answers4

1

This can be fixed very easily using %errorlevel% and an IF statement.

Original script by Jelle Geerts.

@ECHO OFF

:Search
ping -n 1 "xxx.xxx.xxx.xx" | findstr /r /c:"[0-9] *ms"

if %errorlevel% == 0 (
    echo Device was found!
    start airsiren.wav
    pause.
) else (
    goto Search
)
John Kens
  • 1,615
  • 2
  • 10
  • 28
1

I suggest following code:

@echo off
set "LastExitCode=1"
:Loop
%SystemRoot%\System32\ping.exe -n 1 xxx.xxx.xxx.xx | %SystemRoot%\System32\find.exe /C "TTL" >nul
if not %ErrorLevel% == %LastExitCode% set "LastExitCode=%ErrorLevel%" & if %ErrorLevel% == 0 start "Play sound" airsiren.wav
%SystemRoot%\System32\timeout.exe /T 5 /NOBREAK
if not errorlevel 1 goto Loop

PING outputs a line with TTL if there is a response on echo request and exits usually with value 0 on receiving a response and with 1 on getting no response. But PING does not always exit with 0 on a positive response which is the reason for using FIND.

FIND processes the output of PING and searches for lines containing the string TTL. FIND exits with value 0 on finding at least one line with TTL and otherwise with 1 for indicating no line found containing the search string. The output of FIND to handle STDOUT is of no interest and therefore reduced to a minimum by using option /C and redirected to device NUL.

Now the exit code of FIND is compared with an environment variable which holds last exit value of FIND initialized with value 1.

On current exit code being equal last exit code, there is no change in availability of the pinged device on network and therefore nothing to do.

Otherwise on a difference the current exit code is assigned to the environment variable for next loop run and current exit code is compared with value 0. If this second condition is true the pinged device sent the first time a positive response on echo request by PING. In this case the sound is played.

There is nothing else done on pinged device not available anymore on network, i.e. the exit code changes from 0 to 1.

Then a delay of 5 seconds is started using TIMEOUT with giving the user to break it with Ctrl+C. This reduces the processor core usage giving Windows the possibility to use the processor core for other processes and also reduces network usage when the pinged device is available at the moment on network. And of course the pinged device does not need anymore to permanently response on echo requests.

A jump to label Loop is done if TIMEOUT exited normally without a user break. Otherwise on user pressing Ctrl+C the batch file processing also ends.

TIMEOUT with parameter /NOBREAK requires Windows 7 or a later Windows version.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • echo /?
  • find /?
  • goto /?
  • if /?
  • ping /?
  • set /?
  • start /?
  • timeout /?

See also single line with multiple commands using Windows batch file for an explanation of operator & and meaning of if not errorlevel 1.

Mofi
  • 46,139
  • 17
  • 80
  • 143
1

My solution:

@echo off &:: modem_tester_xp+.bat
REM original https://www.elektroda.pl/rtvforum/topic2917839.html
setlocal EnableDelayedExpansion

rem set connection name (for newer than Win XP) from Network Connections (preferred name doesn't have space)
set _connection_name=internet

rem make file which close this script
echo @echo.^>"%~dpn0.exit"^&@del /q "%%~f0">"%~dp0close_%~nx0"

for /f "tokens=2-4 delims==." %%a in ('wmic os get Version /value ^|find "="') do if "%%~c" neq "" set "_system_version=%%~a.%%~b"
set "_con_ip="
set "_my_ip.last="

:start
::-n (seconds+1)
ping 127.0.0.1 >nul -n 3
set "_my_ip="
if not defined _con_ip call :get_con_ip "%_connection_name%"
if defined _con_ip for /f "tokens=3-5 delims= " %%p in ('route print ^|find " 0.0.0.0 "') do if "%%~r" neq "" if /i "%%~p"=="%_con_ip%" ( set "_my_ip=%%~p" ) else if /i "%%~q"=="%_con_ip%" set "_my_ip=%%~q"

rem if connection lost clean variable _my_ip.last
if not defined _my_ip (
    set "_con_ip="
    set "_my_ip.last="
) else if /i "%_my_ip%" neq "%_my_ip.last%" (
    rem remember last connection addres
    set "_my_ip.last=%_my_ip%"
    call :2run
)

if not exist "%~dpn0.exit" goto start
del /q "%~dpn0.exit"
endlocal
goto :eof

:get_con_ip &::ConnectionName:return variable _con_ip
if "%_system_version%"=="5.1" (
    rem XP find modem address
    for /f "tokens=2 delims== " %%a in ('netsh diag show gateway WAN* ^|find "." ^|find "="') do if "!_con_ip!"=="" set "_con_ip=%%~a"
) else (
    rem if newer works like win7, if not: if "%_system_version%"=="6.1" (rem Windows 7
    if "%~1" neq "" for /f "tokens=1,4* delims= " %%n in ('netsh interface ipv4 show interfaces ^|find /i "%~1"') do if "!_con_ip!"=="" if /i "%%~p"=="%~1" for /f "tokens=1* delims=:" %%i in ('netsh interface ipv4 show addresses %%~n ^|find "." ^|find /i "ip"') do if "!_con_ip!"=="" set "_con_ip=%%~j"
    if "!_con_ip!" neq "" set "_con_ip=!_con_ip: =!"
)
goto :eof

:2run
rem run external
rem start "modem started" /min /b cmd /c "echo %date% %time% '%_my_ip%'&pause"
start airsiren.wav
penknife
  • 101
  • 4
1

There are two problems with your code

  • Your code will unconditionally goes to the beginning even after the phone is connected, so it repeats playing the sound. You could use ... && (start airsiren.wav & goto :EOF) to terminate the batch file or use another label other than :EOF to do something else. But this doesn't give you the option to keep monitoring the phone for disconnection and re-connection.

  • You have to check the setting of the default media player (Typically Windows Media Player) and make sure that it is not set to continuously loop or repeat the media. Also it is overkill and somewhat inconvenient to launch a full fledged media player just for playing back a short notification sound, and usually you have to close the media player afterwards.

So this is the code I propose which solves the above mentioned obstacles by providing the option to continuously monitor the phone's connection status and also provide a more programmatic way to play the notification sound in a self contained player by using a hybrid BAT/JSCript solution.

@if (@Code)==(@BatchScript) /* Hybrid BAT/JScript line */

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set @PlaySound=start "" /b cscript //nologo //e:JScript "%~f0"
set "SoundFile.Connect=%SystemRoot%\media\ringout.wav"
set "SoundFile.Disconnect=?"

set "GenFail.Localized.Text=General failure"

:: set to 0 to disable continuous connection monitoring
set "ContinuousMonitoring=1"
set "PhoneIP=xxx.xxx.xxx.xxx"
set "Timeout=3000"

setlocal EnableDelayedExpansion

set "CheckGeneralFailure=1"
echo [%TIME%] Waiting for connection...
:WaitForConnection
ping -n 1 %PhoneIP% -w %Timeout% | findstr "TTL" >nul && (
    echo [!TIME!] Phone Connected.
    !@PlaySound! "!SoundFile.Connect!"
    if %ContinuousMonitoring% NEQ 0 goto :MonitorConnection
    goto :EOF
) || (
    if !CheckGeneralFailure! NEQ 0 (
        ping -n 1 %PhoneIP% -w 100 | findstr /i /c:"%GenFail.Localized.Text%" >nul && (
            ping -n 1 -w %Timeout% 127.255.255.255 >nul
            (call,) %= Set errorlevel to 0 =%
        ) || set "CheckGeneralFailure=0"
    )
    goto :WaitForConnection
)

:MonitorConnection
ping -n 1 %PhoneIP% | findstr "TTL" >nul && (
    ping -n 1 -w %Timeout% 127.255.255.255 >nul
    goto :MonitorConnection
) || (
    echo [!TIME!] Phone Disconnected.
    echo [!TIME!] Waiting for connection...
    set "CheckGeneralFailure=1"
    REM Play another sound for disconnect?
    goto :WaitForConnection
)


goto :EOF
/*** End of batch code ***/
@end
/*** JScript Sound Player ***/

var wmpps = {
    Undefined     : 0,
    Stopped       : 1,
    Paused        : 2,
    Playing       : 3,
    ScanForward   : 4,
    ScanReverse   : 5,
    Buffering     : 6,
    Waiting       : 7,
    MediaEnded    : 8,
    Transitioning : 9,
    Ready         : 10,
    Reconnecting  : 11,
    Last          : 12
};

var SoundFile;
if (WScript.Arguments.length) SoundFile = WScript.Arguments(0);

var WaitCount = 0;
var objPlayer = new ActiveXObject("WMPlayer.OCX.7");

with(objPlayer) {
    URL = SoundFile;
    settings.volume = 100;
    settings.setMode("loop", false);
    controls.play();
    while(playState == wmpps.Transitioning) {
        WaitCount+=1;
        if (WaitCount > 200) break;
        WScript.Sleep(10);
    }
    if (playState == wmpps.Playing) {
        while(playState != wmpps.Stopped) WScript.Sleep(1000);
    }
    close();
}
sst
  • 1,443
  • 1
  • 12
  • 15
  • First thanks for your work i really appreciate it. It doesn't seem to scan continuously. If it finds the phone it instantly closes and no sound got played. Which audiofile do you mean with \media\ringout.wav ? – J4ck Aug 13 '18 at 21:31
  • @J4ck, The audio file is one of the pre-installed notification sounds on windows. it is located at `%SystemRoot%\media` which is usually `C:\Windows\media`. The `%SystemRoot%` variable refers to windows directory. You can use any other audio file you wish, just replace `%SystemRoot%\media\ringout.wav` with path of the audio file you want to use. And It will continuously scan unless you've made changes to code. `set "ContinuousMonitoring=1"` is to control the behavior. when it is set to 1 (or any non zero value) it will continuously scan, and set it to 0 to instantly close when the phone found. – sst Aug 13 '18 at 23:05
  • Are you sure you have copied the whole code from this answer? Did you make any changes to code? For testing proposes the only line you should change is `set "PhoneIP=xxx.xxx.xxx.xxx"` to set it to the IP address of your phone or any network device you want to check. e.g. `set "PhoneIP=192.168.10.42"`. – sst Aug 13 '18 at 23:23
  • Sorry my bad i've overseen half of the mentioned code... Works perfect i love the time stamp idea. Great! What do i have to change to play the sound multiple times like twice or triple? Also i've seen you wrote something about a sound if the device disconnects. Thanks for your work! – J4ck Aug 15 '18 at 16:06